diff options
author | Austin Foxley <afoxley@google.com> | 2023-02-03 21:54:26 +0000 |
---|---|---|
committer | CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-02-03 21:54:26 +0000 |
commit | 5398657e43e127a566bdc201649a7293bf62a865 (patch) | |
tree | e12268a286dec7a160544a00c26445a86c45755f | |
parent | c8107b03c69d8a9affe54e60ddf459db41659840 (diff) | |
download | pigweed-5398657e43e127a566bdc201649a7293bf62a865.tar.gz |
pw_assert: Add option to pw_assert_basic to call _Exit
Add option to exit the pw_assert_basic backend by calling std::_Exit to
exit the program without running atexit handlers or destructors.
This is needed in the following two cases:
In the case of using pw_build's `wrap_abort`, and the `pw_assert_basic`
default backend, assert failures would infinitely recurse calling abort.
In addition, when not using `wrap_abort` some C library implementations
will attempt to take mutexes out, which shouldn't be done in a crash
handler as it may deadlock.
Change-Id: I9839a9b1fb62b89192c019629ef7710beb80f905
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/127191
Reviewed-by: Wyatt Hepler <hepler@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
Pigweed-Auto-Submit: Austin Foxley <afoxley@google.com>
-rw-r--r-- | pw_assert/public/pw_assert/config.h | 19 | ||||
-rw-r--r-- | pw_assert_basic/basic_handler.cc | 34 | ||||
-rw-r--r-- | pw_assert_basic/docs.rst | 31 |
3 files changed, 67 insertions, 17 deletions
diff --git a/pw_assert/public/pw_assert/config.h b/pw_assert/public/pw_assert/config.h index e8a4ef9a5..6b39cecfc 100644 --- a/pw_assert/public/pw_assert/config.h +++ b/pw_assert/public/pw_assert/config.h @@ -34,11 +34,24 @@ #define PW_ASSERT_CAPTURE_VALUES 1 #endif // !defined(PW_ASSERT_CAPTURE_VALUES) -// If 1, call C's standard abort() function on assert failure. -#ifndef PW_ASSERT_BASIC_ABORT -#define PW_ASSERT_BASIC_ABORT 1 +// Modes available for how to end an assert failure for pw_assert_basic. +#define PW_ASSERT_BASIC_ACTION_ABORT 100 +#define PW_ASSERT_BASIC_ACTION_EXIT 101 +#define PW_ASSERT_BASIC_ACTION_LOOP 102 + +#ifdef PW_ASSERT_BASIC_ABORT +#error PW_ASSERT_BASIC_ABORT is deprecated! Use PW_ASSERT_BASIC_ACTION instead. #endif // PW_ASSERT_BASIC_ABORT +// Set to one of the following to define how pw_basic_assert should act after an +// assert failure: +// - PW_ASSERT_BASIC_ACTION_ABORT: Call std::abort() +// - PW_ASSERT_BASIC_ACTION_EXIT: Call std::_Exit(-1) +// - PW_ASSERT_BASIC_ACTION_LOOP: Loop forever +#ifndef PW_ASSERT_BASIC_ACTION +#define PW_ASSERT_BASIC_ACTION PW_ASSERT_BASIC_ACTION_ABORT +#endif // PW_ASSERT_BASIC_ACTION + // Whether to show the CRASH ASCII art banner. #ifndef PW_ASSERT_BASIC_SHOW_BANNER #define PW_ASSERT_BASIC_SHOW_BANNER 1 diff --git a/pw_assert_basic/basic_handler.cc b/pw_assert_basic/basic_handler.cc index 5648a9013..046b10087 100644 --- a/pw_assert_basic/basic_handler.cc +++ b/pw_assert_basic/basic_handler.cc @@ -132,21 +132,27 @@ extern "C" void pw_assert_basic_HandleFailure(const char* file_name, // device. At some point we'll have a reboot BSP function or similar, but for // now this is acceptable since no one is using this basic backend. if (!PW_ASSERT_BASIC_DISABLE_NORETURN) { - if (PW_ASSERT_BASIC_ABORT) { - // abort() doesn't flush stderr/stdout, so manually flush them before - // aborting. abort() is preferred to exit(1) because debuggers catch it. - std::fflush(stderr); - std::fflush(stdout); - std::abort(); - } else { - WriteLine(""); - WriteLine(MAGENTA " HANG TIME" RESET); - WriteLine(""); - WriteLine( - " ... until a debugger joins. System is waiting in a while(1)"); - while (true) { - } +#if (PW_ASSERT_BASIC_ACTION == PW_ASSERT_BASIC_ACTION_ABORT) + // abort() doesn't flush stderr/stdout, so manually flush them before + // aborting. abort() is preferred to exit(1) because debuggers catch it. + std::fflush(stderr); + std::fflush(stdout); + std::abort(); +#elif (PW_ASSERT_BASIC_ACTION == PW_ASSERT_BASIC_ACTION_EXIT) + // Use _Exit to not run destructors or atexit hooks in case they cause + // further crashes. + std::_Exit(-1); +#elif (PW_ASSERT_BASIC_ACTION == PW_ASSERT_BASIC_ACTION_LOOP) + WriteLine(""); + WriteLine(MAGENTA " HANG TIME" RESET); + WriteLine(""); + WriteLine( + " ... until a debugger joins. System is waiting in a while(1)"); + while (true) { } +#else +#error PW_ASSERT_BASIC_ACTION Must be set to valid option. +#endif PW_UNREACHABLE; } else { WriteLine(""); diff --git a/pw_assert_basic/docs.rst b/pw_assert_basic/docs.rst index a06627f9b..1f8885925 100644 --- a/pw_assert_basic/docs.rst +++ b/pw_assert_basic/docs.rst @@ -20,6 +20,37 @@ behavior. intended mostly for ease of initial bringup. We encourage teams to use tokenized asserts since they are much smaller both in terms of ROM and RAM. +---------------------------- +Module Configuration Options +---------------------------- +The following configurations can be adjusted via compile-time configuration of +this module, see the +:ref:`module documentation <module-structure-compile-time-configuration>` for +more details. + +.. c:macro:: PW_ASSERT_BASIC_ACTION + + Controls what happens after an assert failure. Should be set to one of the + following options: + + - PW_ASSERT_BASIC_ACTION_ABORT: Call std::abort() + - PW_ASSERT_BASIC_ACTION_EXIT: Call std::_Exit(-1) + - PW_ASSERT_BASIC_ACTION_LOOP: Loop forever + + Defaults to abort. + +.. c:macro:: PW_ASSERT_BASIC_SHOW_BANNER + + Controls whether ASCII art banner is printed on assert failure. + + This defaults to enabled. + +.. c:macro:: PW_ASSERT_BASIC_USE_COLORS + + Controls whether colors are used in assert message printed to console. + + This defaults to enabled. + .. _module-pw_assert_basic-custom_handler: Custom handler backend example |