I was surprised to find out that JUCE assertions (
jassert) only trigger a crash when attached with a debugger. I’d like debug builds to informatively crash on assertion failures even when a debugger is not attached. This would allow in-house testers to run Debug builds which crash on assertions failure without requiring them to attach a debugger (the testers might not even have a development environment installed).
assert already works this way, and calls
abort() in debug builds regardless of whether a debugger is attached.
If you agree this is something useful to have, I can think of three options:
- Just change the existing behavior so that
jassert always aborts in debug builds, not just when a debugger is attached.
- Same as 1 but add an opt-out macro to revert to the existing behavior (only crash on failed assertion under debugger).
- Add an opt-in macro to turn on the new suggested behavior.
I had thought option 1 is the best, since if you have have debug builds which fail assertions, it’s better they trigger a crash than silently fail. Then I noticed a failed
jassert outputs a log without crashing in debug builds, and maybe that’s a behavior that would sometimes be useful, although probably less often. So now I think option 2 makes the most sense.
I have a strong opinion against option 1 (change to always abort), but I think an opt-in with a macro could be useful.
However, what does an abort help, if you don’t have a debugger attached in the first place?
Ok, collecting a stack-trace could be, what you are after…
Finding out about the failed assert (either know to query the machine’s log and/or have the failure message also outputted in the crash report) instead of it failing silently on the testing machine. And yes, getting a stack trace.
Those are the technical things I’m after; the high-level purpose is to find out about problems during development, when running debug builds on in-house testers’ machines.
Would appreciate a follow up from the JUCE team.
I was about to reply and say that it’s easy enough to make it terminate by using the JUCE_LOG_CURRENT_ASSERTION macro, but actually it’s not set-up to allow you to customise the behaviour of that macro…
What I can do very easily and non-controversially is to push a change so that if you set your own definition for that macro it’ll be used, and then you can make the assertions do whatever you like.
I guess that would allow for even more flexibility, but I still think the default behavior that would be expected by most programmers and testers is for debug builds to terminate on failed
jasserts, even when not attached to a debugger, same as with the standard
assert. So I think adding this macro to configure the default behavior, and expose it in the projucer, without having to go the extra mile and have a fully customized
jassert, would be useful.
If it’s too controversial to make this the default behavior right away, perhaps we can add an opt-in for this behavior right now, and gradually migrate to it being the default? For example, make the opt-in macro available now and make it configurable in the projucer but checked out by default. In the future make it checked in by default. And possibly sometime later after that, remove it and make it always on if everyone agrees that’s the expected behavior.
I tried customizing
JUCE_LOG_CURRENT_ASSERTION, but it’s not very ergonomic.
It would be helpful if setting
JUCE_DISABLE_ASSERTIONS would always completely ifdef-out assertions. Currently, even when
JUCE_DISABLE_ASSERTIONS is set,
JUCE_LOG_CURRENT_ASSERTION, so I have no way of ifdefing-out assertions in production builds if I customize
JUCE_LOG_CURRENT_ASSERTION as proposed.
Why, you might wonder, not just do this (without having to use the
#ifdef JUCE_DEBUG || MY_DEVELOPMENT_MODE_MACRO
#define JUCE_LOG_CURRENT_ASSERTION <something>
JUCE_DEBUG is defined in
juce_PlatformDefs.h, but that’s also where
JUCE_LOG_CURRENT_ASSERTION is then tested for a custom definition (since Jules’s commit following this post) and gets a default definition otherwise which would be used for
jasserts in JUCE library code, which is not the desired outcome.
One more issue:
JUCE_LOG_CURRENT_ASSERTION is used in
juce_PlatformDefs.h with a following semicolon:
#define jassertfalse JUCE_BLOCK_WITH_FORCED_SEMICOLON (JUCE_LOG_CURRENT_ASSERTION; if (juce::juce_isRunningUnderDebugger()) JUCE_BREAK_IN_DEBUGGER; JUCE_ANALYZER_NORETURN)
…but not in the
#define jassertfalse JUCE_BLOCK_WITH_FORCED_SEMICOLON (JUCE_LOG_CURRENT_ASSERTION)
This unfortunately makes customizing
JUCE_LOG_CURRENT_ASSERTION preprocessor definition even less ergonomic. So, dear JUCE team, it would be helpful if you can add the missing column in the
In more grueling detail, customizing
JUCE_LOG_CURRENT_ASSERTION via the Projucer preprocessor definitions doesn’t work for MSVC release builds, since the compiler command-line has no way of escaping semicolons.