【问题标题】:Making sense of the addr2line message with C++ STL使用 C++ STL 理解 addr2line 消息
【发布时间】:2025-12-23 04:20:08
【问题描述】:

我遇到了这种罕见的段错误,在调试它时,我设法从 addr2line 程序中获得了以下输出。

void std::string::_S_copy_chars<__gnu_cxx::__normal_iterator<unsigned char 
const*, std::vector<unsigned char, std::allocator<unsigned char> > > >
(char*, __gnu_cxx::__normal_iterator<unsigned char const*, 
std::vector<unsigned char, std::allocator<unsigned char> > >,
__gnu_cxx::__normal_iterator<unsigned char const*, std::vector<unsigned char, 
std::allocator<unsigned char> > >)
??:?

由于 _S_copy_chars() 是 std::string 中的私有函数,我显然没有直接调用它。但我无法猜测哪个公共函数正在调用它。如果我能弄清楚公共函数,我可以将导致段错误的 null 取消引用归零。

我怀疑下面的代码...

std::string CInProtocolBase::RetrieveStr(std::vector<unsigned 
char>::const_iterator& iter)
{
    unsigned long sizeOfStr;
    const unsigned char& size = *iter;
    memcpy(&sizeOfStr,&size,4);
    sizeOfStr = 
    boost::asio::detail::socket_ops::network_to_host_long(sizeOfStr);
    std::string str(iter+4,iter+4+sizeOfStr); // <= Could this be culprit??
    iter += (4 + sizeOfStr);
    return str;
}

另一个候选人是这样的:

std::string CInProtocolBase::VectorToStr(const std::vector<unsigned char>& vec)
{
    return std::string(vec.begin(),vec.end());
}

【问题讨论】:

  • 您是否尝试过在调试器中捕获崩溃,并查看函数调用堆栈以找出它在代码中发生的位置?
  • 这发生在生产中。我不能在那里使用调试器。段错误消息是我唯一的提示。我试图弄清楚代码的哪一部分导致了这种情况。 addr2line 已将我指向 std::string::_S_copy_chars() 函数。我需要追踪调用它的代码。
  • 并且没有可用于调试版本的核心转储?因为如果你实际上没有调用堆栈,就真的没有办法向上调用堆栈。
  • 不,我只有一个段错误消息。顺便说一句,我用一些额外的信息更新了查询。我怀疑一个功能可能会做到这一点。这是一个 4 岁的代码。

标签: c++ stl addr2line


【解决方案1】:

memcpy(&amp;sizeOfStr,&amp;size,4) 我发现了两个问题。

首先是从一个单字节变量中复制四个字节。那是一个明确的undefined behavior

第二个是sizeOfStr 可能是 8 个字节(在 64 位系统上,GCC 通常有 long 是 64 位)。这将使部分变量未初始化,因此是不确定的,再次导致undefined behavior

使用正常的赋值,让编译器为你正确地进行转换:

sizeOfStr = size;

【讨论】:

  • 这会导致当前的段错误情况吗?它是如何在这台生产服务器上运行了这么几个月的?它不应该从第一天开始影响吗?
  • @Sharath 它确实会导致像您遇到的那样的崩溃。未定义行为的问题在于它可能似乎工作了数年,然后有一天看似无关的东西发生了变化,它不再工作了。
  • 谢谢,让我做这个更改,然后看看是否修复了崩溃。
  • "sizeOfStr = size" 不起作用。 memcpy 仍然是必需的。但我将 unsigned long 更改为 unsigned int。
  • @Sharath “不起作用”是什么意思?即使您将sizeOfStr 更改为unsigned int,您仍然有未定义的行为,因为您从一个字节源复制了四个字节。