I'm working on some code that uses an existing code-base which is now a DLL. What I'm trying to do it to terminate all the threads that are were started, but keep my main program running.
This is the basic structure of the code:
void Mainprogram()
{
tempProcessingThreadHandle = (HMODULE)_beginthread(SomeDLLEntry, 0, (void)&Params); //SomeDLLEntry is a function in some.dll
//Other Code I Want to Run
}
In the DLL:
void SomeDLLEntry()
{
tempProcessingThreadHandle = (HMODULE)_beginthread(SomeOtherDLLThing1, 0, (void)&Params);
tempProcessingThreadHandle = (HMODULE)_beginthread(SomeOtherDLLThing2, 0, (void)&Params);
if (someCondition)
return;
}
void SomeOtherDLLThing1()
{
if (someOtherCondition)
exit(1);
}
I thought that returning from SomeDLLEntry() would cause the threads started in the DLL (SomeOtherDLLThing1 and 2) to terminate as well, but that's not the case, as seen in the debugger; SomeDLLEntry() thread would disappear, but the others are still running.
Now, if I set someOtherCondition to true, and exit(1) is called from SomeOtherDLLThing1(), what should happen? When I debug over this, the debugger seems to crash, but it appears to go past the exit(1) line and give me:
Unhandled exception at 0x6B4E87CD (Mso20win32client.dll) in Mainprogram.exe: 0xC0000005: Access violation reading location 0x0000018C.
Is this because the whole process (including Mainprogram()) has been terminated? What exactly does calling exit(1) in SomeOtherDLLThing1() do? How can I properly terminate all of the DLL-related threads and continue with my Mainprogram()?
The only way to safely terminate threads and continue to execute is to coordinate with those threads, have them cleanly finish, then join the thread handles.
There is no free lunch.
Other choices are "hack, force halt of threads, and pray you get lucky" or "do your work in another process, and pray summary shutdown causes no problems".
I believe that some of the logic that sets R_CStackStart in routine Rf_initialize_R of 'R-3.3.3/src/unix/system.c' does not work when Rf_initEmbeddedR is called from a thread other than the main thread.
In my case the value of R_CStackStart was set by the following line of code in a thread other than the main thread:-
R_CStackStart = (uintptr_t) __libc_stack_end;
But setting R_CStackStart to this value caused R to print the messages "Error: C stack usage <large int> is too close to the limit" followed by a crash at some point before Rf_initEmbeddedR exited.
I was able to get the code to run without error messages or a crash by stepping through it in gdb and setting the value of R_CStackStart back to its default of -1 after the above line of code.
Is this a bug or a feature of the R software in this routine?
I'm using assert from <cassert> to check invariants in my multithreaded C++11 program. When the assertion fails, I'd like to be able to inspect the state of the failing function, along with still-intact backtrace, variable state, etc. at the time of the failed assertion. The issue seems be some interaction between SIGABRT and my threads, as my std::threads are pthread_killed, presumably by some default signal handler. How can I pause gdb right at the time of the failed assertion?
Here are some things I've tried:
set a catchpoint on SIGABRT. This catch does occur, but it's too late (in __pthread_kill).
defined __assert_fail, which is extern declared in <assert.h>, and set a gdb breakpoint on it. This is never caught so presumably the pthread is being killed before this is called (?).
What's the recommended approach here?
I did the following:
Example programm:
#include <cassert>
void f2()
{
assert(0);
}
void f1()
{
f2();
}
int main()
{
f1();
}
Now I set a breakpoint to f2 in hope I can step down to the assert with stepi later:
gdb > break f2
gdb > run
Breakpoint 11, f2 () at main.cpp:5
gdb > stepi // several times!!!!
0x080484b0 in __assert_fail#plt ()
Ahhh! As we can see stepi goes to symbol which tells us that there is a function with that name. So set simply a breakpoint for __assert_fail#plt
gdb > break __assert_fail#plt
gdb > run
Breakpoint 11, f2 () at main.cpp:5
(gdb) bt
#0 0x080484b0 in __assert_fail#plt ()
#1 0x080485f7 in f2 () at main.cpp:5
#2 0x08048602 in f1 () at main.cpp:10
#3 0x0804861b in main () at main.cpp:15
Works for me!
If you need a breakpoint on assert for some reason, Klaus's answer to break on __assert_fail is absolutely correct.
However, it turns out that setting a breakpoint to see stack traces in gdb on multithreaded programs is simply not necessary at all, as gdb already breaks on SIGABRT and switches the the aborting thread. In my case I had a misconfigured set of libraries that lead to this red herring. If you are trying to see stack traces from aborted code (SIGABRT) in gdb using multithreaded programs, you do not need to do anything in gdb, assuming the default signal handlers are in place.
FYI, you can see the default signal handlers by running info signals, and the same for just SIGABRT by running info signals SIGABRT. On my machine, I see this, which shows that the program will be stopped, etc. If for some reason your SIGABRT signal handler is not set up to stop on SIGABRT, you need to change that setting. More info at https://sourceware.org/gdb/onlinedocs/gdb/Signals.html.
(gdb) info signals SIGABRT
Signal Stop Print Pass to program Description
SIGABRT Yes Yes Yes Aborted
There is something strange happening when I try to debug application. Simply the debugger does not stop on breakpoints when I set breakpoints in catch portion of try-catch block.
Here is an example.
try {
throw std::overflow_error("test");
} catch (...) {
qDebug() << "caught"; // HERE, I SET BREAKPOINT ON THIS LINE
}
It prints the "caught" on screen when exception occurs but it does not stop on this line. (If you ever wonder; Yes, I'm building app in Debug mode and running in Debug mode)
Am I suffering from lack of fundamental knowledge about how gdb works? (I mean maybe it does not stop because breakpoints in catch portion does not work)
Any help would be greatly appreciated.
Thanks.
To catch an exception in IDE, you need issue gdb commands directly in gdb console.
Here's link how to get into gdb console in Qt Create IDE:
Accessing gdb console in Qt-Creator
Once you're the type
catch throw
to stop when your program throws an exception or
catch catch
to stop in the catch block.
If you need to catch a specific library exception, read this thread: GDB: How to break when a specific exception type is thrown?
for people using LLDB,
# set on both throw and catch
breakpoint set -E C++ -h true
# or on catch
b __cxa_begin_catch
# or on throw
b __cxa_throw
while will set breakpoints on throw and catch.
#ben sen, I guess any opinization may result in such a behavior. There are many ways how those options can be specified (via environment variables aka CFLAGS or via IDE options to the project), but they all result to some particular -O option given to the compiller command line. Even if nothing is given at all, please check what is the default optimization for your compiller. My proposal would be to explicitely give -O0 to the compiller and check that no other -O options are supplied.
According to the documentation I can break on specific exception type by using conditional breakpoints. However the syntax for the condition isn't very clear to me:
condition bnum <expression>
Looking at the expression syntax I think this is the pattern I need:
{type} addr
However, I don't know what I should pass for the addr argument. I tried the following:
(gdb) catch throw
(gdb) condition 1 boost::bad_function_call *
But it doesn't work (gdb breaks on all exception types).
Can anyone help?
Update
I also tried #Adam's suggestion, but it results in an error message:
(gdb) catch throw boost::bad_function_call
Junk at end of arguments.
Without boost:: namespace:
(gdb) catch throw bad_function_call
Junk at end of arguments.
Workaround
Breaking in the constructor of bad_function_call works.
EDIT
The documentation suggests that catch throw <exceptname> can be used to break whenever an exception of type <exceptname> is thrown; however, that doesn't seem to work in practice.
(gdb) help catch
Set catchpoints to catch events.
Raised signals may be caught:
catch signal - all signals
catch signal <signame> - a particular signal
Raised exceptions may be caught:
catch throw - all exceptions, when thrown
catch throw <exceptname> - a particular exception, when thrown
catch catch - all exceptions, when caught
catch catch <exceptname> - a particular exception, when caught
Thread or process events may be caught:
catch thread_start - any threads, just after creation
catch thread_exit - any threads, just before expiration
catch thread_join - any threads, just after joins
Process events may be caught:
catch start - any processes, just after creation
catch exit - any processes, just before expiration
catch fork - calls to fork()
catch vfork - calls to vfork()
catch exec - calls to exec()
Dynamically-linked library events may be caught:
catch load - loads of any library
catch load <libname> - loads of a particular library
catch unload - unloads of any library
catch unload <libname> - unloads of a particular library
The act of your program's execution stopping may also be caught:
catch stop
C++ exceptions may be caught:
catch throw - all exceptions, when thrown
catch catch - all exceptions, when caught
Ada exceptions may be caught:
catch exception - all exceptions, when raised
catch exception <name> - a particular exception, when raised
catch exception unhandled - all unhandled exceptions, when raised
catch assert - all failed assertions, when raised
Do "help set follow-fork-mode" for info on debugging your program
after a fork or vfork is caught.
Do "help breakpoints" for info on other commands dealing with breakpoints.
When gdb command 'catch throw' fails, try this workaround :
(tested with Linux g++ 4.4.5/gdb 6.6)
1/ Add this code anywhere in the program to debug :
#include <stdexcept>
#include <exception>
#include <typeinfo>
struct __cxa_exception {
std::type_info *inf;
};
struct __cxa_eh_globals {
__cxa_exception *exc;
};
extern "C" __cxa_eh_globals* __cxa_get_globals();
const char* what_exc() {
__cxa_eh_globals* eh = __cxa_get_globals();
if (eh && eh->exc && eh->exc->inf)
return eh->exc->inf->name();
return NULL;
}
2/ In gdb you will then be able to filter exceptions with :
(gdb) break __cxa_begin_catch
(gdb) cond N (what_exc()?strstr(what_exc(),"exception_name"):0!=0)
where N is the breakpoint number, and exception_name is the name of exception for which we wish to break.
From what I have understood from the question here, you want to break when a specific exception boost::bad_function_call is thrown in your application.
$> gdb /path/to/binary
(gdb) break boost::bad_function_call::bad_function_call()
(gdb) run --some-cli-options
So when the temporary object boost::bad_function_call is constructed in preparation for the throw; gdb will break out!
I have tested this and it does work. If you precisely know the way the exception object is being constructed then you can set breakpoint on the specific constructor, otherwise as shown in the example below, you can omit the arguments prototype list, and gdb will set break points on all different flavours of the constructor.
$ gdb /path/to/binary
(gdb) break boost::bad_function_call::bad_function_call
Breakpoint 1 at 0x850f7bf: boost::bad_function_call::bad_function_call. (4 locations)
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y <MULTIPLE>
1.1 y 0x0850f7bf in boost::bad_function_call::bad_function_call() at /usr/include/boost/function/function_base.hpp:742
1.2 y 0x0850fdd5 in boost::bad_function_call::bad_function_call(boost::bad_function_call const&) at /usr/include/boost/function/function_base.hpp:739
1.3 y 0x0863b7d2 <boost::bad_function_call::bad_function_call()+4>
1.4 y 0x086490ee <boost::bad_function_call::bad_function_call(boost::bad_function_call const&)+6>
Another approach is to rely on the tinfo argument available when the catch point is triggered, which is a pointer to the object returned by typeid(type).
So say if I want to catch exception std::bad_alloc being thrown, I could just do:
> p &typeid(std::bad_alloc)
> $1 = (__cxxabiv1::__si_class_type_info *) 0x8c6db60 <typeinfo for std::bad_alloc>
> catch throw if tinfo == 0x8c6db60
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"}
As others already mentioned this functionality doesn't work in practice. But as workaround you can put condition on catch throw. When exception is thrown we come to __cxa_throw function. It has several parameters pointing to exception class, so we can set condition on one of them. In the sample gdb session below, I put condition on dest parameter of __cxa_throw. The only problem is that value of dest (0x80486ec in this case) is unknown in advance. It can be known, for example, by first running gdb without condition on breakpoint.
[root#localhost ~]#
[root#localhost ~]# gdb ./a.out
GNU gdb (GDB) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/a.out...done.
(gdb) catch throw
Catchpoint 1 (throw)
(gdb) condition 1 dest==0x80486ec
No symbol "dest" in current context.
(gdb) r
warning: failed to reevaluate condition for breakpoint 1: No symbol "dest" in current context.
warning: failed to reevaluate condition for breakpoint 1: No symbol "dest" in current context.
warning: failed to reevaluate condition for breakpoint 1: No symbol "dest" in current context.
Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x804a080, tinfo=0x8049ca0, dest=0x80486ec <_ZNSt13runtime_errorD1Ev#plt>) at ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc:68
68 ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc: No such file or directory.
in ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc
(gdb) bt
#0 __cxxabiv1::__cxa_throw (obj=0x804a080, tinfo=0x8049ca0, dest=0x80486ec <_ZNSt13runtime_errorD1Ev#plt>) at ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc:68
#1 0x08048940 in main () at test.cpp:14
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x008d9ddb exception throw
stop only if dest==0x80486ec
breakpoint already hit 1 time
(gdb)
Update
You must also load debug info for libstdc++ for this workaround to work.
I'm not sure if this is a recent fix, but with GDB GNU gdb (Debian 9.1-2) 9.1, I have used catch throw std::logical_error successfully. I would hate to generalise prematurely, but it is possible this now works correctly in GDB (April 2020).
I think I can answer the part about setting conditional breaks. I won't answer question regarding exceptions as __raise_exception seems to not exist in g++ 4.5.2 (?)
Let's assume that you have following code (I use void to get something similar to __raise_exception from gdb doc)
void foo(void* x) {
}
int main() {
foo((void*)1);
foo((void*)2);
}
to break at foo(2) you use following commands
(gdb) break foo
Breakpoint 1 at 0x804851c: file q.cpp, line 20.
(gdb) condition 1 x == 2
If you run with
(gdb) r
you will see that it stops on the second foo call, but not on the first one
I think, what they meant in docs is that you set break on function __raise_exception (very implementation dependent)
/* addr is where the exception identifier is stored
id is the exception identifier. */
void __raise_exception (void **addr, void *id);
and then set conditional break on id as described above (you have to somehow determine what is id for yours exception type).
Unfortunately
(gdb) break __raise_exception
results with (g++ 4.5.2)
Function "__raise_exception" not defined.
In case the problem is that there is no valid stack trace (not breaking in raise), it seems to be a problem when re-compiling without re-starting gdb.
( i.e. calling "make" inside the gdb console).
After having re-started gdb, it breaks correctly in raise.c
(my versions : GNU gdb 8.1.0.20180409-git, gcc 7.4.0, GNU make 4.1)