2017-02-25 54 views
2

按在https://stackoverflow.com/a/11311786/890753 @EvanED我創建了一個GDB命令newstr創建一個新的std :: string,並把它放在一個方便的gdb變量:調用的std ::〜在gdb的basic_string()

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,所以tidyness我還創建delstr

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

它的工作原理,但析構函數調用產生一個惱人的消息:

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

我可以避開「非標轉換」的消息? (我正在使用gdb 7.10。)

+0

另外:在'newstr'我用了一個「轉換爲void」招防止GDB從打印返回值的'調用「命令。但'delstr'中的最後一個命令是一個總是打印設置值的'set'。但我不想'delstr'打印任何東西。我還有另一個可以用來避免打印的技巧嗎? –

+0

其實我最喜歡的是「取消」便利變量,但gdb沒有辦法做到這一點 - 是嗎? –

回答

3

TL; DR:將0傳遞給析構函數,而不是$foo

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參數。


每個人都應該知道,在Italium C++ ABI實際上有three destructorsD0, D1, D2)。

GCC有一個optimization -fdeclone-ctor-dtor,它將三個析構函數的公共部分重構爲"D4" destructor。這個「D4」析構函數需要an extra argument __in_chrg來確定哪個D0/D1/D2是源,以知道是否調用虛擬基本析構函數。

這個「D4」析構函數也以某種方式用作GCC生成的DWARF符號的規範析構函數聲明。如果我們檢查從GDB錯誤報告鏈接的GCC issue,使用「D4」的原因是因爲GCC開發人員不想選擇D0,D1或D2中的哪一個來祝福。

結果是GDB沒有忽略的額外int

__in_chrg值爲2當析構函數能夠「完整的對象的破壞」(D0,D1),並0的時,它僅僅是一個「基礎對象的析構函數」(D2)。由於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; 
} 
相關問題