[Concept,08/17] test: Reset malloc backtrace collection before each test
Commit Message
From: Simon Glass <sjg@chromium.org>
The stack-protector test and __stack_chk_fail() call
malloc_backtrace_skip(true) to prevent crashes when collecting
backtraces from a corrupted stack. However, they never reset it, so all
subsequent allocations in a long-running session (e.g. pytest) have
empty caller backtraces.
Add malloc_backtrace_unbusy() to clear the reentrant guard which can
also get stuck if backtrace collection crashes. Reset both flags at the
start of each test in test_pre_run()
Signed-off-by: Simon Glass <sjg@chromium.org>
---
common/dlmalloc.c | 24 ++++++++++++++++++++++++
include/malloc.h | 30 ++++++++++++++++++++++++++++++
test/test-main.c | 8 ++++++++
3 files changed, 62 insertions(+)
@@ -5986,6 +5986,30 @@ void malloc_backtrace_skip(bool skip)
#endif
}
+void malloc_backtrace_unbusy(void)
+{
+#if CONFIG_IS_ENABLED(MCHECK_BACKTRACE)
+ in_backtrace = false;
+#endif
+}
+
+bool malloc_backtrace_is_active(bool *skipp, bool *busyp)
+{
+#if CONFIG_IS_ENABLED(MCHECK_BACKTRACE)
+ if (skipp)
+ *skipp = mcheck_skip_backtrace;
+ if (busyp)
+ *busyp = in_backtrace;
+ return !mcheck_skip_backtrace && !in_backtrace;
+#else
+ if (skipp)
+ *skipp = false;
+ if (busyp)
+ *busyp = false;
+ return false;
+#endif
+}
+
static const char *mcheck_caller(void)
{
#if CONFIG_IS_ENABLED(MCHECK_BACKTRACE)
@@ -827,10 +827,40 @@ int malloc_log_entry(uint idx, struct mlog_entry **entryp);
*
* @skip: true to skip backtrace collection, false to enable it
*/
+
+/**
+ * malloc_backtrace_unbusy() - Clear the backtrace reentrant guard
+ *
+ * The malloc backtrace collector sets a guard flag while collecting a
+ * backtrace to prevent re-entrancy. If a crash or longjmp occurs during
+ * collection, the guard stays set and all subsequent backtraces are
+ * silently skipped. Call this to reset it.
+ */
+
+/**
+ * malloc_backtrace_is_active() - Check whether backtrace collection works
+ *
+ * @skipp: If non-NULL, returns true if collection is disabled via
+ * malloc_backtrace_skip()
+ * @busyp: If non-NULL, returns true if the reentrant guard is stuck
+ * Return: true if backtrace collection is active (neither skipped nor busy)
+ */
#if CONFIG_IS_ENABLED(MCHECK_HEAP_PROTECTION)
void malloc_backtrace_skip(bool skip);
+void malloc_backtrace_unbusy(void);
+bool malloc_backtrace_is_active(bool *skipp, bool *busyp);
#else
static inline void malloc_backtrace_skip(bool skip) {}
+static inline void malloc_backtrace_unbusy(void) {}
+static inline bool malloc_backtrace_is_active(bool *skipp, bool *busyp)
+{
+ if (skipp)
+ *skipp = false;
+ if (busyp)
+ *busyp = false;
+
+ return false;
+}
#endif
/**
@@ -464,6 +464,14 @@ static int dm_test_restore(struct device_node *of_root)
*/
static int test_pre_run(struct unit_test_state *uts, struct unit_test *test)
{
+ /*
+ * Reset backtrace collection in case a previous test disabled it
+ * (e.g. stack-protector test via __stack_chk_fail) or a crash
+ * left the reentrant guard set.
+ */
+ malloc_backtrace_skip(false);
+ malloc_backtrace_unbusy();
+
ut_assertok(event_init());
/*