Closed DethRaid closed 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.
If you define the symbol
RX_BREAK_ON_ASSERT
, Rex will raise a breakpoint on a failed assert instead ofabort
ing