Reputation: 985
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.
Upvotes: 2
Views: 792
Reputation:
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.
Upvotes: 1