BuckeyeSoftware / rex

rex engine and game
MIT License
15 stars 0 forks source link

Add compile option to break on assert instead of aborting #28

Closed DethRaid closed 4 years ago

DethRaid commented 4 years ago

If you define the symbol RX_BREAK_ON_ASSERT, Rex will raise a breakpoint on a failed assert instead of aborting

graphitemaster commented 4 years ago

The correct place to handle this was in abort rather than assert. Since abort can also be called by non-asserting code. I took it on myself to handle this in a more automated way with commit 920f525 instead. The general idea is to have two abort paths. One for debug and one for release, picked based on RX_DEBUG being defined.

In the debug case we use the platforms' preferred method for triggering a debug trap. This is done with __built_trap for gcc/clang, and __debugbreak for MSVC or Windows. These intrinsics compile directly down to a hardware breakpoint, which all debuggers automatically handle.

In the release case we want a proper, no-message, no-fuss, quick abort. This is done with raise(SIGABRT) for POSIX, and exit(2) on Windows. There's a couple reasons for doing things this way, which I'm listing here for reference:

C standard's abort is not really consistent across platforms. Some debuggers on POSIX systems automatically set breakpoints for it inside the C standard library runtime. This means running a release build in a debugger would lead to automatic breakpoint. We don't want to encourage running release builds in a debugger.

A similar story exists on Windows when it comes to C standard's abort. There's no signal for SIGABRT on Windows at all, instead abort is treated as a special termination request for the process that allows the debugger to trap it, which isn't ideal. This is what leads to the infamous message box to the user

"This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information."

The only way to avoid this is to use the _set_abort_behavior interface to disable such message. This isn't a thread-safe interface and early-init can fail in other threads before we can make such a call. It's made more annoying by the fact that Windows will try to record the fault in Windows Event Viewer through Watson crash dump reporter tool. We don't want to support such concepts. The choice of exit is a good solution instead. The value of 2 is chosen because this is an abnormal termination and the values 0 and 1 are reserved for EXIT_SUCCESS and EXIT_FAILURE, respectively.