段错误使用C++ STL地图找由于进程退出时的静态变量清理

问题描述:

我做了以下功能的STL地图,所有这一切都是由一个互斥保护上的操作: -段错误使用C++ 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; 
} 

有没有任何方式来防止这种情况?我可以分配持有的活性地图单身,但我会尽量避免使用单身

+2

Valgrind this ... – Velkan

+0

无法用当前单元测试重现 –

+1

您的示例代码应该是最小的但是完整的!没有人可以重现你的问题。 –

失败的最有可能的一点是在你的release回调erase调用,因为它是唯一的接入点,您的地图已经没有了任何防范机制。你确定在这一点上你的WatchCtx是地图的关键的一部分?如果没有,这听起来可能是插入已经放手。但是,就像Velkan已经说过的那样,valgrind(或者您选择的调试器)会给你带来确定性。

+1

是不是由unique_lock保护?也许我误解了这是如何工作的 –

+0

@Bug杀手锁同时从多个访问保护地图。它并不能保护它不会让它不在地图中的位置(例如,如果它从未被正确添加)。我不知道该程序的上下文并充分调用约束来验证或伪造。如果您在调用“擦除”之前使用“find”检查密钥,并且错误停止,我会查看您的插入例程或者您确定何时删除“WatchCtx”的方式。 – starturtle

+0

我认为使用不存在的键调用擦除是安全的:[695754] –