C STL映射中的SegFault由于过程退出期间的静态可变清理而找到

Segfault in c++ stl map find due to static variable cleanup during process exit

本文关键字:静态 退出 SegFault 映射 STL 于过程 过程      更新时间:2023-10-16

i在以下功能中在stl映射上进行操作,所有这些功能都受穆特克斯的保护: -

static std::mutex track_active_lock_mtx;
typedef intrusive_ptr<WatchCtxInternal> WatchCtxInternal_h;
static std::map<WatchCtxInternal*, WatchCtxInternal_h> actives;
void* get_ptr(WatchCtxInternal_h ctx) 
{
    unique_lock<mutex> trackActiveLock(track_active_lock_mtx);
    if(actives.find(ctx.get()) == actives.end()) {
        actives.insert(make_pair(ctx.get(), ctx));
    }    
    trackActiveLock.unlock();
    return ctx.get();
}
void genericWatcher(void *watcherCtx)
{
    unique_lock<mutex> trackActiveLock(track_active_lock_mtx);
    auto it = actives.find((WatchCtxInternal*)watcherCtx);
    if (it == actives.end()) {          
        return;
    }
    //do unrelated stuff
    actives.erase(it);
}

我在第一个功能中有分割故障: -

Program terminated with signal SIGSEGV, Segmentation fault.
#0  _M_lower_bound (this=<optimized out>, __k=<optimized out>, __y=0xf31256e8, __x=0x65687465) at /volume/evo/files/opt/poky/1.8.2-4/sysroots/i586-poky-linux/usr/include/c++/4.9.2/bits/stl_tree.h:1261
1261            if (!_M_impl._M_key_compare(_S_key(__x), __k))
(gdb) bt
#0  _M_lower_bound (this=<optimized out>, __k=<optimized out>, __y=0xf31256e8, __x=0x65687465) at /volume/evo/files/opt/poky/1.8.2-4/sysroots/i586-poky-linux/usr/include/c++/4.9.2/bits/stl_tree.h:1261
#1  find (__k=<optimized out>, this=0xf6ac8e2c <actives>) at /volume/evo/files/opt/poky/1.8.2-4/sysroots/i586-poky-linux/usr/include/c++/4.9.2/bits/stl_tree.h:1913
#2  find (__x=<optimized out>, this=0xf6ac8e2c <actives>) at /volume/evo/files/opt/poky/1.8.2-4/sysroots/i586-poky-linux/usr/include/c++/4.9.2/bits/stl_map.h:860
#3  get_ptr (ctx=...) 
(gdb)fr 3
(gdb) p ctx
$4 = {px = 0xf3124d30}

编辑:我设法使用Memcheck工具获得了堆栈跟踪。发生的事情是,作为过程退出的一部分,静态图被清理了,但是在完全退出之前,在另一个线程中发生了对genericwatcher的回调: -

main.cpp

static void thread1(void *arg) {
    //call genericWatcher repeatedly
}
int main() {
    if(fork() == 0) {
       pthread_create(..., thread1,..)
       //call get_ptr() repeatedly
    }
    return 0;
}

有什么方法可以防止这种情况?我可以分配一个持有活跃物图的单身人士,但我试图避免使用单例

最可能的故障点是release回调中的erase调用,因为它是地图上没有任何守卫机制的唯一访问点。您确定您的WatchCtx是地图密钥的一部分吗?如果没有,听起来插入已经放开了。但是,就像Velkan已经说过的那样,Valgrind(或您选择的调试器)将为您确定。