【问题标题】:Debugging an assertion with gdb shows weird std::string size使用 gdb 调试断言显示奇怪的 std::string 大小
【发布时间】:2015-05-19 23:10:55
【问题描述】:

我对 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
$1 = (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
$2 = 180
(gdb) print bufferSize
$3 = 4096
(gdb) print size
$4 = 171791040

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

我在 gdb 方面的成就和专家地位还很遥远,所以我的第一个问题是我是否做错了什么。也许大小不是运行时的真正价值?

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

谢谢!

【问题讨论】:

  • 你得到的大小可能是(unsigned long)-1 或类似的东西。这意味着大小已损坏,因为内存已损坏。
  • 你在编译时使用的是什么优化级别?
  • 你应该发布 MCVE,否则我们只是在这里猜测,问题可能出在调用上下文中。
  • 尝试直接从 gdb 提示符调用str.size(),如下所示:(gdb) print str.size()
  • ForceBru 我无法将该数字与任何有意义的东西(如-1)匹配,因为大小并不总是相同,也许我错了..我不知道。 Vaughn Cato 我正在使用 2 级。Slava 我无法发布 MCVE,因为我无法重现该错误,它有时会发生,但我无法定义何时。 ks1322,我不能打印 str.size() 因为 gdb 说我需要一个正在运行的进程来调试。

标签: c++ gdb assert core


【解决方案1】:

有几种方法可以发生这种情况。

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

或者,也许有什么东西在你的堆上乱写并覆盖了存储字符串大小的内存位置,所以虽然内容仍然只有 7 个字节长,但大小成员已经被垃圾覆盖了。

或者str 可能只是一个悬空引用,_M_p 指向的内存仍然包含字符串“NOT-SET”,但包含 size 成员的内存已被重新用于其他用途。

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

【讨论】:

  • 嗨乔纳森!遗憾的是我无法使用 Valgrind,因为它只发生在生产中(我无法重现它),而且程序是在它下面运行的乌龟。我接受了这个答案,因为我认为这三个选项之一是我的错误。现在我必须找到哪一个。有没有办法在运行时保存它?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多