2017-02-25 2 views
2

Per @EvanED in https://stackoverflow.com/a/11311786/890753 I newstr einen gdb-Befehl erstellt eine neue std :: string zu erstellen und sie in einer GDB Bequemlichkeit Variable setzen:Aufruf std :: ~ basic_string() in 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 

Es funktioniert super:

(gdb) newstr $foo "hello world" 
(gdb) p $foo->c_str() 
$57 = 0xb22e388 "hello world" 

I newstr in anderen benutzerdefinierten gDB-Befehle zur Verfügung, so dass für tidyness ich auch delstr erstellt:

define delstr 
call ($arg0)->~basic_string($arg0) 
call free($arg0) 
set ($arg0)=(void*)0 
end 

Es funktioniert, aber die Destruktoraufrufs erzeugt eine ärgerliche Nachricht:

(gdb) delstr $foo 
warning: Using non-standard conversion to match method std::string::~basic_string to supplied arguments 
$62 = 0 

Kann ich die „Nicht-Standard-Konvertierung“ Meldung vermeiden? (Ich verwende gdb 7.10.)

+0

auch: In 'newstr' ich eine "cast void" verwendet Trick gdb zu verhindern, dass das Drucken der Rückgabewert von einem' Rufbefehl. Aber der letzte Befehl in 'delstr' ist ein' set', der immer den eingestellten Wert ausgibt. Aber ich will nicht, dass dstrstr etwas druckt. Gibt es einen anderen Trick, den ich verwenden kann, um diesen Druck zu vermeiden? –

+0

Eigentlich würde ich _really_ gerne die Convenience-Variable "aufheben", aber gdb hat keine Möglichkeit das zu tun - oder? –

Antwort

3

TL; DR: Übergeben Sie 0 an den Destruktor anstelle von $foo.

define delstr 
call ($arg0)->~basic_string(0) 
#       ^
call free($arg0) 
set ($arg0)=(void*)0 
end 

OK so, was los ist ... Wir können zunächst die Unterzeichnung eines destructor überprüfen. Es dauert in der Tat eine ganze Zahl:

(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 ist die „Nicht-Standard-Konvertierung“ Warnung über einen Zeiger auf eine ganze Zahl Umwandlung, die in der Tat nicht Standard ist. (Die Warnung hat nichts mit dem Destruktor zu tun.)

Aber aus welchem ​​Grund müssen wir eine extra ganze Zahl an den Destruktor übergeben? Stellt sich heraus, es ist ... a bug Ein GCC-Problem (ab gcc 6.3.0) tatsächlich, weil das gleiche Programm kompiliert mit clang (ab clang 3.8.1) hat nicht das zusätzliche int Argument.


Man sollte wissen, dass in der Italium C++ ABI gibt es tatsächlich three destructors (D0, D1, D2).

GCC hat eine optimization -fdeclone-ctor-dtor, die die gemeinsamen Teile der drei Destruktoren in eine refaktoriert. Dieser "D4" -Destruktor benötigt an extra argument __in_chrg, um zu bestimmen, welcher von D0/D1/D2 die Quelle ist, um zu wissen, ob die Destruktoren der virtuellen Basis aufgerufen werden sollen.

Dieser "D4" -Destruktor wird irgendwie auch als kanonische Destruktor-Deklaration des von GCC generierten DWARF-Symbols verwendet. Wenn wir den GCC issue Link aus dem GDB-Fehlerbericht überprüfen, liegt der Grund für die Verwendung von "D4" darin, dass die GCC-Entwickler nicht auswählen wollten, welche von D0, D1 oder D2 zu segnen ist. Das Ergebnis ist ein extra int, das GDB nicht ignoriert hat.

__in_chrg Der Wert ist, wenn der 2 destructor von „vollständiger Objekt Zerstörung“ fähig ist, (D0, D1) und 0 wenn es nur ein „Basisobjekt destructor“ (D2) ist. Da eine std::string keine virtuellen Basisklassen hat, sollten Sie einfach 0 an dieses Argument übergeben.


Hinweis: benutzte ich dieses Programm gegen GDB zu testen:

#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; 
} 
Verwandte Themen