__builtin_return_address でデストラクタの呼び出し元を調べてみる

プログラムのテストをしていて、core を吐かずに動作はしているんだけど、なんでそこでデストラクタが呼ばれるのかわからない(微妙)って状況に陥りました。人の実装を引き継いだりフレームワーク的なものを使っていて、オブジェクトの解放のタイミングをいまいち把握し切れていないみたいな感じです。

デストラクタがどこで呼ばれているのかがわかればいいのになあってことで調べてみると、glibc には backtrace っつう便利な関数があるらしいのですが、FreeBSD 上で実装しているので使えません。

というわけで gcc の組み込み関数、__builtin_return_address を使ってみることにしました。

C++:
  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. class hoge {
  6. public:
  7.     hoge() {}
  8.     ~hoge();
  9.  
  10.     void hello() { cout <<"hoge" <<endl; }
  11. };
  12.  
  13. hoge::~hoge() {
  14.     cerr <<__builtin_return_address(0) <<endl;
  15.     cerr <<__builtin_return_address(1) <<endl;
  16.     cerr <<__builtin_return_address(2) <<endl;
  17. }
  18.  
  19. void func() {
  20.     hoge h;
  21.     h.hello();
  22. }
  23.  
  24. int main(int argc, char* argv[]) {
  25.     func();
  26.  
  27.     return 0;
  28. }

こんな感じのソース test.cc があったとして、g++ -g test.cc -o test でビルド。./test で実行してみると、以下のように出力されました。

CODE:
  1. hoge
  2. 0x10007f3
  3. 0x100082f
  4. 0x1000666

hoge の下の行の 0x10007f3 がデストラクタの呼び出し元のアドレスというわけで、gdb ./test で見てみます。"list *アドレス" でそのあたりのソースを見ることができます。

CODE:
  1. (gdb) list *0x10007f3
  2. 0x10007f3 is in func(void) (test.cc:21).
  3. 16          cerr <<__builtin_return_address(2) <<endl;
  4. 17      }
  5. 18
  6. 19      void func() {
  7. 20          hoge h;
  8. 21          h.hello();
  9. 22      }
  10. 23
  11. 24      int main(int argc, char* argv[]) {
  12. 25          func();

この出力を見ると、test.cc の 21 行目の後にデストラクタが呼び出されているのがわかるという寸法です。にゃるほど。


About this entry