【问题标题】:Getting SIGSEGV in std::map, when using find function使用 find 函数时在 std::map 中获取 SIGSEGV
【发布时间】:2017-08-16 13:05:44
【问题描述】:

我正在运行一些小型在线游戏,并且有时服务器崩溃。我找不到导致 SIGSEGV 的原因。 gdb 把我带到那个功能:

bool Player::getStorageValue(const uint32_t key, int32_t& value) const
{
    auto it = storageMap.find(key);
    if (it == storageMap.end()) {
        value = -1;
        return false;
}

    value = it->second;
    return true;
}

我能否以某种方式更好地保护它,不让程序尝试访问内存的受限区域?

这是我的 gdb 日志:

(gdb) bt full
#0  0x000000000054503c in std::less<unsigned int>::operator()(unsigned int const&, unsigned int const&) const ()
No symbol table info available.
#1  0x0000000000740dca in std::_Rb_tree<unsigned int, std::pair<unsigned int const, int>, std::_Select1st<std::pair<unsigned int const, int> >, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, int> > >::_M_lower_bound(std::_Rb_tree_node<std::pair<unsigned int const, int> > const*, std::_Rb_tree_node<std::pair<unsigned int const, int> > const*, unsigned int const&) const ()
No symbol table info available.
#2  0x000000000073e145 in std::_Rb_tree<unsigned int, std::pair<unsigned int const, int>, std::_Select1st<std::pair<unsigned int const, int> >, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, int> > >::find(unsigned int const&) const ()
No symbol table info available.
#3  0x000000000073c46f in std::map<unsigned int, int, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, int> > >::find(unsigned int const&) const ()
No symbol table info available.
#4  0x000000000072dfa2 in Player::getStorageValue(unsigned int, int&) const ()
No symbol table info available.
#5  0x00000000006b2890 in LuaScriptInterface::luaPlayerGetStorageValue(lua_State*) ()

我已将互斥锁添加到代码中,以防止线程同时尝试某些元素

bool Player::getStorageValue(const uint32_t key, int32_t& value) const
{
    std::lock_guard<std::mutex> lockClass(mutex_gp13);

    auto it = storageMap.find(key);
    if (it == storageMap.end()) {
        value = -1;
        return false;
    }

    value = it->second;
    return true;
}

虽然这应该可以解决我的问题,但今天与那个 gdb 日志有相同的 SIGSEGV。

编辑: 我发现我没有将互斥锁放在写入地图的函数上。我现在要试试这个。

【问题讨论】:

  • 您的地图似乎已损坏。这里的代码没问题。

标签: c++ gdb stdmap segmentation-fault


【解决方案1】:

鉴于这是一个服务器,我想你可能是多线程的。如果是这种情况,可能是在您设置返回值之前您的地图正在某处被更改,从而导致您的迭代器变得无效。然后你访问无效的迭代器,程序就死了。

如果是这种情况,那么您需要使用信号量等保护它免受更改。如果不是,那么我们可能需要更多信息,因为代码看起来不错。

【讨论】:

  • 所以主要问题是一些线程可能同时在那里编辑一些元素?那我试试把互斥锁放在那里。
  • 我以为没关系,2天没有出现错误,但是今天我刚刚遇到了一个相同的gdb日志。 Mutex 在这里没有帮助我,这很奇怪。
  • 我发现我的互斥锁不能正常工作,现在用更好的测试一下
  • @Piodo 关于互斥锁和信号量的建议。我倾向于通过对外部线程正在访问的每个成员变量或成员变量组使用互斥锁来避免以后出现问题。适当地命名它们,以便您知道哪个互斥锁锁定了哪个变量或组。小心线程锁。由外部线程进行过多处理可能会导致您将线程锁定在每个等待另一个完成的位置。始终在同一功能中锁定和解锁。最后,练习。线程是困难的。学习线程更难。不要放弃。
【解决方案2】:

此服务器是 Open Tibia Server,调用后我从 gdb 获得了相同的堆栈:

player->getStorageValue(123, value)

player 上,它是 Player* 并指向已删除的变量。 C++ 代码很好,互斥锁无法修复它。

问题在于服务器加载的 LUA 脚本,它可能会调用已删除对象的函数。我在这里描述了 LUA 脚本中的常见错误:https://halp.skalski.pro/2020/06/05/tfs-1-x-how-to-not-write-lua-scripts-or-how-to-crash-server-by-lua-script/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-02
    • 1970-01-01
    • 1970-01-01
    • 2021-11-12
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    • 2020-08-21
    相关资源
    最近更新 更多