GDB 报告 c++ 中参数的地址错误对象的构造函数

发布于 2024-12-28 17:17:44 字数 4711 浏览 0 评论 0原文

我遇到了 GDB 将字符串作为参数传递给构造函数的奇怪行为。 代码工作正常,但是当我在调试器中单步执行时,GDB 似乎认为我的参数位于不同的地址。有谁知道这是怎么回事?

这是我可以创建的最简单的程序来演示该问题:

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ nl gdb_weird.cpp
     1  #include <iostream>
     2  #include <string>
     3
     4  class C
     5  {
     6  public:
     7     C(std::string str)
     8     {
     9        std::string* str_ptr = &str;
    10        std::cout << "Address of str: " << &str << std::endl;
    11        std::cout << "Address in str_ptr: " << str_ptr << std::endl;
    12        std::cout << "Value of str: " << str << std::endl;
    13     };
    14  };
    15
    16  int main(int, char*[])
    17  {
    18     std::string s("Hello, World!");
    19     C c(s);
    20     return 0;
    21  }

使用调试信息进行编译,不进行优化。
请注意,我在为 x86、x64 和 mingw(x86) 编译时看到此问题。
我没有尝试过其他架构。

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ g++ -O0 -g -Wall -Wextra gdb_weird.cpp -m32

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ g++ --version
g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

现在,调试:

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ gdb a.out
GNU gdb (Ubuntu/Linaro 7.3-0ubuntu2) 7.3-2011.08
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/jwcacces/a.out...done.

(gdb) br main
Breakpoint 1 at 0x80488ce: file gdb_weird.cpp, line 18.

(gdb) run
Starting program: /home/jwcacces/a.out

Breakpoint 1, main () at gdb_weird.cpp:18
18         std::string s("Hello, World!");

(gdb) next
19         C c(s);

(gdb) step
C::C (this=0xffffd74f, str=...) at gdb_weird.cpp:9
9             std::string* str_ptr = &str;

奇怪的是,当我尝试输出 str 时,我得到垃圾:

(gdb) output str
{
  static npos = <optimized out>,
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>},
                                           <No data fields>},
                 _M_p = 0xffffd748 "\024\260\004\b\364\177\354\367\360\211\004\b\364\177\354", <incomplete sequence \367>
                }
}

那么,GDB 认为 str 的地址是什么?

(gdb) output &str
(std::string *) 0xffffd734

程序认为str的地址是什么?

(gdb) next
10            std::cout << "Address of str: " << &str << std::endl;

(gdb) next
Address of str: 0xffffd748
11            std::cout << "Address in str_ptr: " << str_ptr << std::endl;

(gdb) next
Address in str_ptr: 0xffffd748
12            std::cout << "Value of str: " << str << std::endl;

这真的很奇怪,程序认为str0xffffd748,但gdb认为它在0xffffd734
而且,当您输出位于 0xffffd748 的字符串对象时,它可以正常工作。

(gdb) output *(std::string*)0xffffd748
{
  static npos = <optimized out>,
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, 
                                           <No data fields>
                                          },
                 _M_p = 0x804b014 "Hello, World!"
                }
}

并且程序本身使用参数没有问题:

(gdb) next
Value of str: Hello, World!
13         };

(gdb) continue
Continuing.
[Inferior 1 (process 19463) exited normally]

(gdb) quit

我尝试将构造函数参数的类型更改为 int、struct、指针,但我无法重现奇怪的情况。
另外,我尝试将调试格式设置为-ggdb。

问题:

  • 这是怎么回事?
  • 为什么 gdb 说 std::string 的 npos 成员已优化(可能是从库中优化),这与它有什么关系吗?
  • 这只是巧合吗,在 GDB 认为 str 所在的“对象”中,_M_p 成员指向 0xffffd748 地址str 实际上位于?
  • 在其他什么情况下会出现这种行为?

---- 哇,突破 ----
如果我将调试格式设置为 -gstabs+,GDB 会正确获取 str 的地址。
这是否意味着gdb调试格式不能正常工作?

I'm experiencing a weird behavior with GDB passing a string as the parameter to a constructor.
The code works fine, but when I step through in the debugger, GDB seems to think my parameter is at a different address then it is. Does anyone know what's going on here?

Here's the simplest program I can create that demonstrates the problem:

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ nl gdb_weird.cpp
     1  #include <iostream>
     2  #include <string>
     3
     4  class C
     5  {
     6  public:
     7     C(std::string str)
     8     {
     9        std::string* str_ptr = &str;
    10        std::cout << "Address of str: " << &str << std::endl;
    11        std::cout << "Address in str_ptr: " << str_ptr << std::endl;
    12        std::cout << "Value of str: " << str << std::endl;
    13     };
    14  };
    15
    16  int main(int, char*[])
    17  {
    18     std::string s("Hello, World!");
    19     C c(s);
    20     return 0;
    21  }

Compile with debugging info, no optimization.
Note, that I see this problem when compiled for x86, x64, and mingw(x86).
I have not tried other architectures.

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ g++ -O0 -g -Wall -Wextra gdb_weird.cpp -m32

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ g++ --version
g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Now, debug:

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ gdb a.out
GNU gdb (Ubuntu/Linaro 7.3-0ubuntu2) 7.3-2011.08
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/jwcacces/a.out...done.

(gdb) br main
Breakpoint 1 at 0x80488ce: file gdb_weird.cpp, line 18.

(gdb) run
Starting program: /home/jwcacces/a.out

Breakpoint 1, main () at gdb_weird.cpp:18
18         std::string s("Hello, World!");

(gdb) next
19         C c(s);

(gdb) step
C::C (this=0xffffd74f, str=...) at gdb_weird.cpp:9
9             std::string* str_ptr = &str;

Here's the weirdness, when I try to output str, I get garbage:

(gdb) output str
{
  static npos = <optimized out>,
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>},
                                           <No data fields>},
                 _M_p = 0xffffd748 "\024\260\004\b\364\177\354\367\360\211\004\b\364\177\354", <incomplete sequence \367>
                }
}

So, what does GDB think the address of str is?

(gdb) output &str
(std::string *) 0xffffd734

And what does the program think the address of str is?

(gdb) next
10            std::cout << "Address of str: " << &str << std::endl;

(gdb) next
Address of str: 0xffffd748
11            std::cout << "Address in str_ptr: " << str_ptr << std::endl;

(gdb) next
Address in str_ptr: 0xffffd748
12            std::cout << "Value of str: " << str << std::endl;

This is really strange, the program thinks str is at 0xffffd748, but gdb thinks its at 0xffffd734
And, when you output the string object that would be at 0xffffd748 it works correctly.

(gdb) output *(std::string*)0xffffd748
{
  static npos = <optimized out>,
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, 
                                           <No data fields>
                                          },
                 _M_p = 0x804b014 "Hello, World!"
                }
}

And the program itself hs no problem using the parameter:

(gdb) next
Value of str: Hello, World!
13         };

(gdb) continue
Continuing.
[Inferior 1 (process 19463) exited normally]

(gdb) quit

I have tried changing the type of the constructor parameter to an int, a struct, a pointer, but I can not reproduce the weirdness.
Also, I have tried setting the debugging format to -ggdb.

Questions:

  • What's going on here?
  • Why does gdb say that std::string's npos member is optimized out (optimized out of library maybe), and does that have anything to do with it?
  • Is it just a coincidence that in the "object" that would be where GDB thinks str is, the _M_p member points to 0xffffd748, the address that str actually is located at?
  • In what other circumstances with this behavior happen?

---- WOAH, Breakthrough ----
If I set the debugging format to -gstabs+, GDB gets the address of str right.
Does this mean that the gdb debugging format does not work correctly?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

对岸观火 2025-01-04 17:17:44

来自任何帖子(https://gcc.gnu.org/ml/gcc /2001-04/msg01037.html)在调试 C++ 时,-gstabs 或 -gstabs+ 似乎是正确的标志。我希望这能有所帮助。

From any post (https://gcc.gnu.org/ml/gcc/2001-04/msg01037.html) it seems that -gstabs or -gstabs+ are the correct flags when debugging C++. I hope this can help.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文