23

gcc provides additional builtin functions "for optimization".

One of them is void __builtin_trap (void) which essentially is here to abort the program by executing an illegal command.

From the doc:

__builtin_trap function causes the program to exit abnormally. GCC implements this function by using a target-dependent mechanism (such as intentionally executing an illegal instruction) or by calling abort. The mechanism used may vary from release to release so you should not rely on any particular implementation.

Why would you ever use this rather than exit(1) or abort? Why did the gcc developers see this as an optimization function?

DevShark
  • 8,558
  • 9
  • 32
  • 56
  • Maybe for easy post-mortem debugging? – Sebastian Hoffmann Mar 01 '16 at 22:22
  • 1
    If I was building a system with high uptime requirements, in stress testing calling __builtin_trap() at random intervals would be a brutal and effective way to test a supervisor - multiple worker process model. – Jarra McIntyre Mar 01 '16 at 22:33
  • You mean rather than `abort()`? – Barry Mar 01 '16 at 22:34
  • Yes, exit(1) or abort would be alternatives. – DevShark Mar 01 '16 at 22:35
  • If I were to implement C++ exceptions (or something similar) and I wanted the C++11 optimization that uncaught exceptions lead to immediate termination, possibly without cleanup ( https://akrzemi1.wordpress.com/2011/06/10/using-noexcept/ "violation of `noexcept` specification now would result in calling `std::terminate` and the program would have the freedom to not unwind the stack. ... This guarantees that the exception will not get out of `noexcept` function ... while still allowing compiler no-throw optimizations."), I would use `__builtin_trap()` to allow those "no-throw optimizations." – Max Lybbert Mar 01 '16 at 23:06

2 Answers2

15

Because exit(1) causes the program to terminate normally with an error status code. See the cppreference page. In contrast __builtin_trap causes the program to terminate abnormally.

The simplest way to see the differences is to look at the guarantees made by exit, if doing one of those things is something you don't want to happen, __builtin_trap would be better.

Debugging is the most common example, as __builtin_trap could trigger a debugger to dump the process, while exit would not (since the program terminates "normally" with an error).

Guvante
  • 18,775
  • 1
  • 33
  • 64
  • 5
    `abort` would be a more portable way in regular of killing the process immediately due to a bug; `__builtin_trap`, I suspect, is there because `abort` is a library function and GCC can't always count on linking on the standard library. – Colonel Thirty Two Mar 01 '16 at 22:29
  • @ColonelThirtyTwo this leads to another question: how would you implement `abort`? – Revolver_Ocelot Mar 01 '16 at 23:43
  • 2
    @Revolver_Ocelot glibc on Linux implements it by removing all signal handlers and then sending the process a `SIGTRAP` signal, which terminates the process (though debuggers usually break instead). It also afterwards sends itself `SIGKILL`, then infinite loops, just in case. I imagine that `__builtin_trap` instead uses a trap instruction, where available. – Colonel Thirty Two Mar 01 '16 at 23:46
6

The __builtin functions are not necessarily for optimisation - they are for "doing things that the compiler can't do directly from source code", including support for "special instructions" and "architecture-specific operations". One of the main purposes of __builtin functions is that the compiler will "know" what these do at a later stage. Although there are "library optimisations" in the compiler, the compiler can use __builtin functions much more freely to determine that the behaviour is something specific - for example, __builtin_trap can be relied upon to "not continue to the next instruction", so the compiler doesn't have to worry about code like:

if (x <= 0.0) __builtin_trap();
y = ln(x);

It can then make use of the "fast inline version of ln", since the error has been caught already.

Note also that __builtin_trap is almost guaranteed to end up as a "stop" in the debugger, where exit(1) or some such will just exit the program with a "not success" result code, which is rather annoying if you are trying to figure out where that math error message came from...

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • You could trap the signal (`SIGILL` usually) that `__builtin_trap()` generates and continue execution. For example, a debugger could do that. So in general, it can't be assumed that `x > 0.0` after the trap. – Björn Lindqvist Nov 08 '16 at 01:04
  • 4
    I guarantee that the compiler WILL assume that `__builtin_trap` won't continue - yes, you can trap it, and you can continue, but since the compiler doesn't expect it, you get what you deserve, and it will still assume `x > 0.0`. The `__builtin_trap` is how a compiler knows you're using for example `assert`. – Mats Petersson Nov 08 '16 at 07:28