Вопрос

I'm working for a small software firm that is making windows applications with and IDE developed by that firm, which lacks support for Valgrind or C runtime debug libraries. We have written a primitive memory leak detection program for C that works by setting a breakpoint just before main() exits and inspecting a linked list (which keeps track of memory allocation and deallocation) for unfreed memory. We would like to add C++ support, but since memory deallocation can happen after main() returns within destructors of global variables, adding a breakpoint at the end of main no longer works out.

So I'd like to know if there's a way to add a breakpoint after static object destruction? The compiler we are using is Clang, by the way.

Это было полезно?

Решение

C++ Static objects are destructed in exit(). You can put a breakpoint on _exit() and at this moment all your static objects must be destructed.

Please see backtraces in a test program on Linux compiled with сlang++:

struct C {
  C() :
    ptr (new int)
  {
  }

  ~C()
  {
    delete ptr;
  }
  int *ptr;
};

C c;

int main()
{
  return 0;
}

This is a gdb script:

set breakpoint pending on
b _exit
command
bt
c
end

b C::~C
command
bt
c
end

b free
command
bt
c
end

r

And this is a test itself:

gdb -q -x test.gdb  ./a.out
Reading symbols from /import/home/sergey.kurenkov/src/linux.x64.6.0/tests/test.break_after_static/a.out...done.
Function "_exit" not defined.
Breakpoint 1 (_exit) pending.
Breakpoint 2 at 0x400680: C::~C. (2 locations)
Function "free" not defined.
Breakpoint 3 (free) pending.

Breakpoint 2, C::~C (this=0x600be8 <c>) at main.cpp:8
8         {
#0  C::~C (this=0x600be8 <c>) at main.cpp:8
#1  0x0000003c41235db2 in exit () from /lib64/libc.so.6
#2  0x0000003c4121ece4 in __libc_start_main () from /lib64/libc.so.6
#3  0x0000000000400519 in _start ()

Breakpoint 2, C::~C (this=0x600be8 <c>) at main.cpp:9
9           delete ptr;
#0  C::~C (this=0x600be8 <c>) at main.cpp:9
#1  0x0000000000400685 in C::~C (this=0x600be8 <c>) at main.cpp:8
#2  0x0000003c41235db2 in exit () from /lib64/libc.so.6
#3  0x0000003c4121ece4 in __libc_start_main () from /lib64/libc.so.6
#4  0x0000000000400519 in _start ()

Breakpoint 3, 0x0000003c4127a950 in free () from /lib64/libc.so.6
#0  0x0000003c4127a950 in free () from /lib64/libc.so.6
#1  0x00000000004006c0 in C::~C (this=0x600be8 <c>) at main.cpp:9
#2  0x0000000000400685 in C::~C (this=0x600be8 <c>) at main.cpp:8
#3  0x0000003c41235db2 in exit () from /lib64/libc.so.6
#4  0x0000003c4121ece4 in __libc_start_main () from /lib64/libc.so.6
#5  0x0000000000400519 in _start ()

Breakpoint 1, 0x0000003c412abc30 in _exit () from /lib64/libc.so.6
#0  0x0000003c412abc30 in _exit () from /lib64/libc.so.6
#1  0x0000003c41235d62 in exit () from /lib64/libc.so.6
#2  0x0000003c4121ece4 in __libc_start_main () from /lib64/libc.so.6
#3  0x0000000000400519 in _start ()
[Inferior 1 (process 13558) exited normally]
(gdb)

As you can see C::~C() is called in exit(), C::~C() itself calls free() and then _exit() is called. So put a breakpoint on _exit() and inspect your linked list as you do it. If I understand you correctly your linked list must be a global variable.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top