Let's assume you have the following code.cpp with a thread that throws an exception:
#include <iostream>
#include <thread>
void thr()
{
while (true) {
new int[1000000000000ul];
}
}
int main(int argc, char* argv[]) {
std::thread t(thr);
t.join();
std::cout << "Hello, World!" << std::endl;
return 0;
}
Compile it with using the following CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(tutorial)
set(CMAKE_CXX_STANDARD 11)
add_executable(test_exceptions main.cpp)
target_link_libraries(test stdc++ pthread)
Now you can play with, running it will give you an abort because of bad_alloc.
Before going on, it's better if you install libstd debug symbols, sudo apt-get install libstdc++6-5-dbg
or whatever version you have.
Debug compilation
If you are compiling in Debug
you can follow this answer https://stackoverflow.com/a/12434170/5639395 because constructors are usually defined.
Release compilation
If you are compiling in DebWithRelInfo
you may not be able to find a proper constructor where to put your breakpoint because of the compiler optimization. In this case, you have some other options. Let's continue.
Source code change solution
If you can change the source code easily, this will work https://stackoverflow.com/a/9363680/5639395
Gdb catch throw easy solution
If you don't want to change the code, you can try to see if catch throw bad_alloc
or in general catch throw exception_name
works.
Gdb catch throw workaround
I will build on top of this answer https://stackoverflow.com/a/6849989/5639395
We will add a breakpoint in gdb in the function __cxxabiv1::__cxa_throw
. This function takes a parameter called tinfo
that has the information we need to conditionally check for the exception we care about.
We want something like catch throw if exception==bad_alloc, so how to find the proper comparison?
It turns out that tinfo
is a pointer to a structure that has a variable called __name
inside. This variable has a string with the mangled name of the exception type.
So we can do something like: catch throw if tinfo->__name == mangled_exception_name
We are almost there!
We need a way to do string comparison, and it turns out gdb has a built-in function $_streq(str1,str2) that does exactly what we need.
The mangled name of the exception is a little harder to find, but you can try to guess it or check the Appendix of this answer. Let's assume for now it is "St9bad_alloc".
The final instruction is:
catch throw if $_streq(tinfo->__name , "St9bad_alloc")
or equivalent
break __cxxabiv1::__cxa_throw if $_streq(tinfo->__name , "St9bad_alloc")
How to find the name of your exception
You have two options
Look for the symbol in the library
Assuming that you installed the libstd debug symbols, you can find the library name like this:
apt search libstd | grep dbg | grep installed
The name is something like this libstdc++6-5-dbg
Now check the files installed:
dpkg -L libstdc++6-5-dbg
Look for something that has a debug in the path, and a .so extension. In my pc I have /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21
.
Finally, look for the exception you want in there.
nm /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21 | grep -i bad_alloc
Or
nm /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21 | grep -i runtime_error
etc.
In my case I found something like 00000000003a4b20 V _ZTISt9bad_alloc
which suggested me to use "St9bad_alloc" as the name.
Throw it in gdb and inspect the name in there
This is easy, just start gdb, catch throw
everything and run the small executable I wrote before. When you are inside gdb, you can issue a p *tinfo
and look for the __name
description from gdb.
gdb -ex 'file test_exceptions' -ex 'catch throw' -ex 'run'
(gdb) p *tinfo
$1 = {_vptr.type_info = 0x406260 <vtable for __cxxabiv1::__si_class_type_info+16>,
__name = 0x7ffff7b8ae78 <typeinfo name for std::bad_alloc> "St9bad_alloc"}