Solve the problem of probabilistic crash and save failure when orbslam3 saves the map, segment fault (core dumped) Segmentation fault(core dumped)

1. Question

  • orbslam3 has added the function of map saving, loading and reuse. You can slowly build a map of the environment, and directly use the old map for subsequent tasks to reduce computing power consumption.
    • ORB_SLAM3 map saving and loading: https://blog.csdn.net/weixin_44675820/article/details/125076927
  • However, there is a high probability of Segmentation fault(core dumped) when saving the map, which leads to the direct loss of the hard-working map.

2. Check

  1. Through gdb debugging, the output stack information is as follows:
    • gdb debug executable program with parameters: https://blog.csdn.net/weixin_43667077
Thread 1 "Mono" received signal SIGSEGV, Segmentation fault.
__GI___pthread_mutex_lock (mutex=0x707070707070957) at ../nptl/pthread_mutex_lock.c:67
67 ../nptl/pthread_mutex_lock.c: No such file or directory.
(gdb) bt
#0 0x00007ffff37ecfd0 in __GI___pthread_mutex_lock (mutex=0x707070707070957)
    at ../nptl/pthread_mutex_lock.c:67
#1 0x00007ffff668580d in void std::lock<std::unique_lock<std::mutex>, std::unique_lock<std::mutex>>(std::unique_lock<std::mutex> & amp;, std:: unique_lock<std::mutex> & amp;) ()
    at /home/nav/catkin_ws/src/orbslam3/orbslam3/../lib/libORB_SLAM3.so
#2 0x00007ffff668174f in ORB_SLAM3::MapPoint::isBad() ()
    at /home/nav/catkin_ws/src/orbslam3/orbslam3/../lib/libORB_SLAM3.so
#3 0x00007ffff6697f57 in ORB_SLAM3::Map::PreSave(std::set<ORB_SLAM3::GeometricCamera*, std::less<ORB_SLAM3::GeometricCamera*>, std::allocator<ORB_SLAM3::GeometricCamera*> > & amp; ) ()
    at /home/nav/catkin_ws/src/orbslam3/orbslam3/../lib/libORB_SLAM3.so
#4 0x00007ffff66951f5 in ORB_SLAM3::Atlas::PreSave() ()
    at /home/nav/catkin_ws/src/orbslam3/orbslam3/../lib/libORB_SLAM3.so
#5 0x00007ffff65f54f2 in ORB_SLAM3::System::SaveAtlas(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) ()
    at /home/nav/catkin_ws/src/orbslam3/orbslam3/../lib/libORB_SLAM3.so
#6 0x0000555555567ebf in main()
  1. It can be roughly seen that during the process of saving the map System::SaveAtlas(), a mutex occurred in the MapPoint::isBad() function ( pthread_mutex_lock) error.
  2. Further analysis and discussions with developers on github, I understand that the root cause of the problem is EraseObservationMap::PreSave and MapPoint::PreSave functions The > operation removes elements while traversing, causing a crash.
    • github discussion: https://github.com/UZ-SLAMLab/ORB_SLAM3/issues/443

3. Solve

  • The general solution of personal understanding is to put mspMapPoints before the Map::PreSave and MapPoint::PreSave function EraseObservation operation code> backup in the temporary set, then traverse the temporary set, and perform EraseObservation operation on the real set.
  • According to the solution of https://github.com/UZ-SLAMLab/ORB_SLAM3/issues/443#issuecomment-1154814254, replace Map.cc's Map::PreSave and MapPoint.cc's MapPoint::PreSave function.
  • The content of the function that has been carried over and will not crash is as follows:
void Map::PreSave(std::set<GeometricCamera*> & amp;spCams)
{<!-- -->
    int nMPWithoutObs = 0;

    std::set<MapPoint*> tmp_mspMapPoints1;
    tmp_mspMapPoints1.insert(mspMapPoints.begin(), mspMapPoints.end());

    for(MapPoint* pMPi : tmp_mspMapPoints1)
    {<!-- -->
        if(!pMPi || pMPi->isBad())
            continue;

        if(pMPi->GetObservations(). size() == 0)
        {<!-- -->
            nMPWithoutObs++;
        }
        map<KeyFrame*, std::tuple<int,int>> mpObs = pMPi->GetObservations();
        for(map<KeyFrame*, std::tuple<int,int>>::iterator it= mpObs.begin(), end=mpObs.end(); it!=end; + + it)
        {<!-- -->
            if(it->first->GetMap() != this || it->first->isBad())
            {<!-- -->
                pMPi->EraseObservation(it->first);
            }

        }
    }

    // Saves the id of KF origins
    mvBackupKeyFrameOriginsId. clear();
    mvBackupKeyFrameOriginsId.reserve(mvpKeyFrameOrigins.size());
    for(int i = 0, numEl = mvpKeyFrameOrigins. size(); i < numEl; + + i)
    {<!-- -->
        mvBackupKeyFrameOriginsId.push_back(mvpKeyFrameOrigins[i]->mnId);
    }


    // Backup of MapPoints
    mvpBackupMapPoints. clear();

    std::set<MapPoint*> tmp_mspMapPoints2;
    tmp_mspMapPoints2.insert(mspMapPoints.begin(), mspMapPoints.end());

    for(MapPoint* pMPi : tmp_mspMapPoints2)
    {<!-- -->
        if(!pMPi || pMPi->isBad())
            continue;

        mvpBackupMapPoints.push_back(pMPi);
        pMPi->PreSave(mspKeyFrames,mspMapPoints);
    }

    // Backup of KeyFrames
    mvpBackupKeyFrames. clear();
    for(KeyFrame* pKFi : mspKeyFrames)
    {<!-- -->
        if(!pKFi || pKFi->isBad())
            continue;

        mvpBackupKeyFrames.push_back(pKFi);
        pKFi->PreSave(mspKeyFrames,mspMapPoints, spCams);
    }

    mnBackupKFinitialID = -1;
    if(mpKFinitial)
    {<!-- -->
        mnBackupKFinitialID = mpKFinitial->mnId;
    }

    mnBackupKFlowerID = -1;
    if(mpKFlowerID)
    {<!-- -->
        mnBackupKFlowerID = mpKFlowerID->mnId;
    }

}
void MapPoint::PreSave(set<KeyFrame*> & amp; spKF,set<MapPoint*> & amp; spMP)
{<!-- -->
    mBackupReplacedId = -1;
    if(mpReplaced & amp; & amp; spMP.find(mpReplaced) != spMP.end())
        mBackupReplacedId = mpReplaced->mnId;

    mBackupObservationsId1. clear();
    mBackupObservationsId2. clear();
    // Save the id and position in each KF who view it
    std::map<KeyFrame*,std::tuple<int,int> > tmp_mObservations;
    tmp_mObservations.insert(mObservations.begin(), mObservations.end());

    for(std::map<KeyFrame*,std::tuple<int,int> >::const_iterator it = tmp_mObservations.begin(), end = tmp_mObservations.end(); it != end; + + it)
    {<!-- -->
        KeyFrame* pKFi = it->first;
        if(spKF.find(pKFi) != spKF.end())
        {<!-- -->
            mBackupObservationsId1[it->first->mnId] = get<0>(it->second);
            mBackupObservationsId2[it->first->mnId] = get<1>(it->second);
        }
        else
        {<!-- -->
            EraseObservation(pKFi);
        }
    }

    // Save the id of the reference KF
    if(spKF.find(mpRefKF) != spKF.end())
    {<!-- -->
        mBackupRefKFId = mpRefKF->mnId;
    }
}