30

I am attempting to capture failed asserts in my program. I’m using a library that makes direct calls to assert(), rather than a custom function or macro, and it is within this library I am currently trying to trace several porting-related bugs. Everything involved has been compiled with debug symbols in g++.

The best solution I have found is breaking at the file:line of the assert, with the condition of the assert expression. This allows stopping on the assert before it fails, but is a horrible solution. It requires special setup for each possibly-failing assert, won’t work from my IDE, and is far too much effort in general.

How can I break on any failed assert using gdb & gcc in such a way that allows examination of the callstack and variables within the scope of the assert call?

It would be even better if the solution allowed me to discard the assert's failure and continue running.

  • On Windows in Visual Studio, breaking is the default behaviour of a failed `assert`. I'm surprised that's not the case in the *nix world - what does a failed `assert` normally do there? – Angew is no longer proud of SO Nov 11 '15 at 09:04
  • 6
    In gdb, before the program is run, you can use `break abort` (or just `b abort`) to add a breakpoint at the function abort(). That will at least let you make a backtrace when an assertion fails (assuming it calls `abort()` when it does; some implementations may call `exit()` instead). Not sure about continuing execution though. – notmyfriend Nov 11 '15 at 09:14
  • 2
    Normally this works by default, as assert() calls abort, and abort raises the SIGABRT signal, and gdb by default breaks on that signal, allowing you to inspect the stack, move up/down the stack e.g. to your function containing the assert() and inspect variables and so on. – nos Nov 11 '15 at 11:42
  • 3
    @notmyfriend In my implementation, it's not the default to break on failed asserts/aborts, it seems; possibly because this is an MSYS2-MinGW setup, although I could swear this happened once on Linux for me. In any case, `break abort` seems to have worked, and works from my IDE as well. If you want to format that into an answer, I will accept it. –  Nov 11 '15 at 16:54
  • @WilliamKappler seems like you should just write up the answer yourself and accept it yourself - I'm sure there's some sort of badge you can get. ;-). I had the same question for MinGW. – Peter M Jul 19 '16 at 15:42

4 Answers4

37

Setting a breakpoint on abort() seems to be the best answer.

break abort in gdb's CLI.

Peter M
  • 1,918
  • 16
  • 24
  • The original poster and @notmyfriend both posted answers in their comments, but after suggesting someone write an official answer, and being back to this page a few times whenever I forgot, and then having to re-read all the comments to figure out what it was, I'm just writing it up! – Peter M Nov 14 '16 at 17:01
  • 4
    This is genius! – Antonio Dec 14 '16 at 10:31
12

No break is needed on Linux, just type bt on the prompt

abort() causes the SIGABRT signal to be raised in Linux, and GDB already breaks on signals by default. E.g.:

a.c

#include <assert.h>

void g(int i) {
    assert(0);
}

void f(int i) {
    g(i);
}

int main(void) {
    f(1);
}

Then:

gcc -std=c99 -O0 -ggdb3 -o a a.c
gdb -ex run ./a

Then just type bt in the shell:

(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:58
#1  0x00007ffff7a483ea in __GI_abort () at abort.c:89
#2  0x00007ffff7a3ebb7 in __assert_fail_base (fmt=<optimized out>, assertion=assertion@entry=0x555555554788 "0", file=file@entry=0x555555554784 "a.c", line=line@entry=4, 
    function=function@entry=0x55555555478a <__PRETTY_FUNCTION__.1772> "g") at assert.c:92
#3  0x00007ffff7a3ec62 in __GI___assert_fail (assertion=0x555555554788 "0", file=0x555555554784 "a.c", line=4, function=0x55555555478a <__PRETTY_FUNCTION__.1772> "g")
    at assert.c:101
#4  0x00005555555546ca in g (i=1) at a.c:4
#5  0x00005555555546df in f (i=1) at a.c:8
#6  0x00005555555546f0 in main () at a.c:12

Which already shows the function values (f (i=1)).

And you can also do as usual:

(gdb) f 4
#4  0x00005555555546ca in g (i=1) at a.c:4
4           assert(0);
(gdb) p i
$1 = 1

The setting that controls if GDB breaks on signals by default or not is: handle all nostop as shown at: How to handle all signals in GDB

Tested in Ubuntu 16.10, gdb 7.11.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • 2
    Note: on some platforms (e.g. MinGW under certain Windows shells) gdb doesn't see a SIGABRT signal so the program just dies on the assert without stopping gdb but setting a breakpoint on abort still works. – Anon Mar 11 '18 at 17:45
  • One notable exception is running tests in GTest, so you might still want to set a breakpoint on `abort` when debugging your tests. – Tom Dec 21 '19 at 04:29
3

If suggested above answers doesn't work for you, you may try to break on __assert_fail function.

break __assert_fail

Name is most probably implementation - dependent, but it's easy to find if you look at definition of assert macro on your platform. This will allow you to break before SIGABRT.

Islam Boziev
  • 167
  • 1
  • 8
0

Another option in code:

#include <windows.h>
#include <signal.h>

static void abortHandler(int signalNumber)
{
    DebugBreak();
}

int main()
{
    signal(SIGABRT, &abortHandler);
}
orgads
  • 678
  • 8
  • 21