草庐IT

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

coder 2024-02-06 原文

当 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、结构、指针,但我无法重现这种怪异现象。
另外,我尝试将调试格式设置为 -ggdb。

问题:

  • 这是怎么回事?
  • 为什么 gdb 说 std::stringnpos 成员被优化掉了(也许是从库中优化出来的),这与它有什么关系吗?
  • 在 GDB 认为 str 所在的“对象”中,_M_p 成员指向 0xffffd748 只是巧合吗,str实际所在的地址?
  • 在其他什么情况下会发生这种行为?

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

最佳答案

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

关于c++ - GDB 报告 C++ 对象的构造函数中的参数地址错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8980566/

有关c++ - GDB 报告 C++ 对象的构造函数中的参数地址错误的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  5. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  6. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  7. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  8. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  9. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  10. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

随机推荐