Add libbacktrace fallback for stack traces on musl/Alpine#3581
Add libbacktrace fallback for stack traces on musl/Alpine#3581hanxizh9910 wants to merge 3 commits intovalkey-io:unstablefrom
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## unstable #3581 +/- ##
=========================================
Coverage 76.63% 76.64%
=========================================
Files 160 160
Lines 80472 80472
=========================================
+ Hits 61668 61674 +6
+ Misses 18804 18798 -6
🚀 New features to boost your workflow:
|
8b39249 to
8bbe43f
Compare
Signed-off-by: Hanxi Zhang <hanxizh@amazon.com>
Signed-off-by: Hanxi Zhang <hanxizh@amazon.com>
Signed-off-by: Hanxi Zhang <hanxizh@amazon.com>
836b39d to
71ae67a
Compare
There was a problem hiding this comment.
This looks like a good change! Thanks for the fix 😊 I just had a couple ideas to simplify/document a little more.
I'm wondering why the stack trace in your testing was so short. Normally I'd expect it to be somewhat longer. Maybe if you built with CFLAGS="-g" there would be more info. I don't think this is too important though.
| bt_frame_state = backtrace_create_state(NULL, 0, bt_simple_error_cb, NULL); | ||
| } | ||
|
|
||
| static int valkey_backtrace(void **trace, int max_size) { |
There was a problem hiding this comment.
It might be worth adding a comment here explaining that we preallocate bt_frame_state because allocating is unsafe while handling an async signal (such as crash handling). This probably isn't immediately obvious and might help out the next person to read this code
| #ifdef HAVE_BACKTRACE | ||
| #define BACKTRACE_MAX_SIZE 100 | ||
|
|
||
| #if defined(USE_LIBBACKTRACE) && !defined(HAVE_EXECINFO) |
There was a problem hiding this comment.
When USE_LIBBACKTRACE is enabled, we should use backtrace_simple() from libbacktrace for frame collection unconditionally — not just when execinfo.h is missing. Both call _Unwind_Backtrace() under the hood, so there's no benefit to keeping the glibc path as a special case. This simplifies the guard here to just #ifdef USE_LIBBACKTRACE
Problem
On Alpine Linux (musl-based), execinfo.h is not available, so Valkey produces no stack trace on crash. This makes debugging crashes on Alpine very difficult.
Solution
Add libbacktrace as a fallback for stack frame collection on systems without execinfo.h.
src/config.h: Split HAVE_BACKTRACE (generic capability) from HAVE_EXECINFO (execinfo-specific). When USE_LIBBACKTRACE is defined and HAVE_EXECINFO is not, HAVE_BACKTRACE is still set so the crash handler compiles in on Alpine.src/debug.c:src/server.c/src/server.h: Initialize backtrace_state once at startup via initLibbacktraceFrameState() to avoid calling malloc from the signal handler, which could deadlock if a crash occurs while the allocator lock is held.Notes
Testing
Built on Alpine 3.23 with USE_LIBBACKTRACE=yes and triggered a crash via DEBUG SEGFAULT. Stack traces are produced correctly for all threads.