根据@evaned在https://stackoverflow.com/a/a/11311786/890753中,我创建了一个GDB命令newstr
创建新的std :: string string string,并将其放入GDB便利性中变量:
define newstr
set ($arg0)=(std::string*)malloc(sizeof(std::string))
call ($arg0)->basic_string()
# 'assign' returns *this; casting return to void avoids printing of the struct.
call (void)( ($arg0)->assign($arg1) )
end
它的作用很棒:
(gdb) newstr $foo "hello world"
(gdb) p $foo->c_str()
$57 = 0xb22e388 "hello world"
我在其他自定义GDB命令中使用newstr
,因此,为了整理我,我还创建了delstr
:
define delstr
call ($arg0)->~basic_string($arg0)
call free($arg0)
set ($arg0)=(void*)0
end
它有效,但是destructor调用会产生一个烦人的消息:
(gdb) delstr $foo
warning: Using non-standard conversion to match method std::string::~basic_string to supplied arguments
$62 = 0
我可以避免"非标准转换"消息?(我正在使用GDB 7.10。)
tl; dr:将 0
传递给破坏者,而不是 $foo
。 define delstr
call ($arg0)->~basic_string(0)
# ^
call free($arg0)
set ($arg0)=(void*)0
end
define delstr
call ($arg0)->~basic_string(0)
# ^
call free($arg0)
set ($arg0)=(void*)0
end
好吧,这是怎么回事...我们可以首先检查灾难的签名。确实需要一个整数:
(gdb) p ((Foo*) 0)->~Foo
$1 = {void (Foo * const, int)} 0x555555554c00 <Foo::~Foo()>
(gdb) p (('std::__cxx11::string'*) 0)->~basic_string
$2 = {void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > * const, int)} 0x7ffff7b75010 <std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()>
(gdb) ptype Foo
type = struct Foo {
public:
Foo(void);
~Foo(int);
}
因此,"非标准转换"警告是将指针转换为整数,这确实是非标准的。(警告与破坏者无关。)
但是,出于什么深刻的理由,我们首先需要将一个额外的整数传递给灾难?事实证明,这是…a bug 😃gcc问题(从GCC 6.3.0开始),因为使用clang编译的同一程序(截至clang 3.8.1)没有额外的int
参数。
应该知道,在意大利C ABI中,实际上有三个破坏者(D0,D1,D2)。
GCC具有优化的-fdeclone-ctor-dtor
,该优化将三个破坏者的共同部分重构为" D4"驱动器。此" D4"驱动器需要一个额外的参数__in_chrg
来确定D0/D1/D2的哪个是来源的,知道是否调用虚拟基础攻击器。
此" D4"驱仪也以某种方式用作GCC生成的矮符号的规范驱动器声明。如果我们检查GDB错误报告链接的GCC问题,则使用" D4"的原因是因为GCC开发人员不想选择D0,D1或D2的哪个来祝福。
结果是一个额外的int
,GDB并未忽略。
当破坏者能够"完全对象破坏"(D0,D1)和0
时,__in_chrg
值是2
。由于std::string
没有虚拟基类,因此您应该将0
传递给该参数。
注意:我使用此程序对GDB进行测试:
#include <string>
#include <iostream>
std::string aa;
struct Foo {
Foo() { std::cout << "Constructing: this = " << this << std::endl; }
~Foo() { std::cout << "Destroying: this = " << this << std::endl; }
};
int main() {
Foo foo;
return 0;
}