Reputation: 1649
As per @EvanED in https://stackoverflow.com/a/11311786/890753 I created a gdb command newstr
to create a new std::string and put it in a gdb convenience variable:
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
It works great:
(gdb) newstr $foo "hello world"
(gdb) p $foo->c_str()
$57 = 0xb22e388 "hello world"
I use newstr
in other custom gdb commands, so for tidyness I also created delstr
:
define delstr
call ($arg0)->~basic_string($arg0)
call free($arg0)
set ($arg0)=(void*)0
end
It works, but the destructor call produces an annoying message:
(gdb) delstr $foo
warning: Using non-standard conversion to match method std::string::~basic_string to supplied arguments
$62 = 0
Can I avoid the "non-standard conversion" message? (I'm using gdb 7.10.)
Upvotes: 3
Views: 1013
Reputation: 523574
0
to the destructor, instead of $foo
.define delstr
call ($arg0)->~basic_string(0)
# ^
call free($arg0)
set ($arg0)=(void*)0
end
OK so what is going on... We can first check the signature of a destructor. It indeed takes an integer:
(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);
}
So the "non-standard conversion" warning is about converting a pointer to an integer, which is indeed non-standard. (The warning has nothing to do with the destructor.)
But for what profound reason do we need to pass an extra integer to the destructor in the first place? Turns out it is … a bug 😃 A GCC issue (as of gcc 6.3.0) actually, because the same program compiled using clang (as of clang 3.8.1) does not have that extra int
argument.
One should know that, in the Italium C++ ABI there are actually three destructors (D0, D1, D2).
GCC has an optimization -fdeclone-ctor-dtor
which refactors the common parts of the three destructors into a "D4" destructor. This "D4" destructor takes an extra argument __in_chrg
to determine which of D0/D1/D2 is the source, to know whether to call the virtual base destructors.
This "D4" destructor is somehow also used as the canonical destructor declaration of the DWARF symbol generated by GCC. If we check the GCC issue linked from the GDB bug report, the reason of using "D4" is because the GCC developers didn't want to pick which of D0, D1 or D2 to bless.
And the result is an extra int
which GDB didn't ignore.
The __in_chrg
value is 2
when the destructor is capable of "complete object destruction" (D0, D1), and 0
when it is just a "base object destructor" (D2). Since a std::string
does not have virtual base classes, you should just pass 0
to that argument.
Note: I used this program to test against 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;
}
Upvotes: 6