使用 gdb 调试断言显示奇怪的 std::string 大小

Debugging an assertion with gdb shows weird std::string size

我在 C++ 程序中遇到断言问题。

HA_Archive & HA_Archive::operator << (const string & str) {
    buffer[wcursor] = HA_TYPE_STRING;
    wcursor++;
    unsigned size = str.size();
    CASSERT((bufferSize > wcursor + size),"buffer exceeds the maximum");

CASSERT 是一个简单的断言,问题就出在这里。

程序留下了我用gdb调试过的核心转储,我发现了一些奇怪的东西。

Program terminated with signal 6, Aborted.
#0  0xb7766424 in __kernel_vsyscall ()
(gdb) bt
#0  0xb7766424 in __kernel_vsyscall ()
#1  0xb6cd1cb1 in raise () from /lib/libc.so.6
#2  0xb6cd33e8 in abort () from /lib/libc.so.6
#3  0xb6ccb58c in __assert_fail () from /lib/libc.so.6
#4  0x086c6dbd in HA_Archive::operator<< (this=0xb2610fb8, str=@0xb49e1f08) at HA_Archive.cxx:94
#5  0x0849b4d3 in PortDriver::serialize (this=0xb49e1ed8, ar=@0xb2610fb8) at PortDriver.cxx:624
#6  0x0838ed80 in PortSession::serialize (this=0xb49e1630, ar=@0xb2610fb8) at PortSession/PortSession.h:71

(gdb) frame 4
#4  0x086c6dbd in HA_Archive::operator<< (this=0xb2610fb8, str=@0xb49e1f08) at HA_Archive.cxx:94
94  HA_Archive.cxx: No such file or directory.
    in HA_Archive.cxx
(gdb) print str
 = (const string &) @0xb49e1f08: {static npos = 4294967295, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0xb322f9b4 "NOT-SET"}}
(gdb) print wcursor
 = 180
(gdb) print bufferSize
 = 4096
(gdb) print size
 = 171791040

打印 str 我可以看到它有 "NOT-SET" 没问题,但是当我打印变量时sizestr.size()价值巨大!显然是make asserts失败的原因,因为bufferSize是4096而wcursor只有180.

我还远未成为 gdb 专家,所以我的第一个问题是我是否做错了什么。也许大小不是运行时的真实值?

我的第二个问题是:如果 gdb 显示了正确的大小值,为什么我在打印时正确地看到了字符串 "NOT-SET",但大小是那么大的数字?

谢谢!

有几种方法可以实现。

字符串实际上可能是那个大小,但内容可能在 str[7] 处有一个 nul 字符,这将导致 GDB 停止打印它。

或者可能有什么东西在您的堆上涂鸦并覆盖了存储字符串大小的内存位置,因此尽管内容仍然只有 7 个字节长,但 size 成员已被垃圾覆盖。

或者 str 可能只是一个悬垂引用并且 _M_p 指向的内存仍然包含字符串 "NOT-SET" 但包含 size 成员的内存已被重新用于别的。

我会在 valgrind 下尝试 运行 以确保没有可能覆盖成员的缓冲区溢出或释放后使用错误。