aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAustin Foxley <afoxley@google.com>2023-02-03 21:54:26 +0000
committerCQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-02-03 21:54:26 +0000
commit5398657e43e127a566bdc201649a7293bf62a865 (patch)
treee12268a286dec7a160544a00c26445a86c45755f
parentc8107b03c69d8a9affe54e60ddf459db41659840 (diff)
downloadpigweed-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.h19
-rw-r--r--pw_assert_basic/basic_handler.cc34
-rw-r--r--pw_assert_basic/docs.rst31
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