diff --git a/CHANGELOG.md b/CHANGELOG.md index a00fbf426f..083c0be152 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +**Fixes**: + +- Linux/ARM32: prevent recursive crashes when libunwind receives an unmapped initial instruction pointer during crash handling. ([#1977](https://github.com/getsentry/sentry-native/pull/1977)) + ## 0.16.3 **Features**: diff --git a/src/unwinder/sentry_unwinder_libunwind.c b/src/unwinder/sentry_unwinder_libunwind.c index 997c65e6e5..9a154608c8 100644 --- a/src/unwinder/sentry_unwinder_libunwind.c +++ b/src/unwinder/sentry_unwinder_libunwind.c @@ -191,6 +191,12 @@ sentry__unwind_stack_libunwind( if (n < max_frames) { ptrs[n++] = (void *)ip; } + + mem_range_t code = { 0, 0 }; + if (uctx && !find_mem_range((uintptr_t)ip, &code)) { + return n; + } + unw_word_t sp = 0; (void)unw_get_reg(&cursor, UNW_REG_SP, &sp); diff --git a/tests/unit/test_unwinder.c b/tests/unit/test_unwinder.c index 07fb2a0a7c..1e6bf0ae7d 100644 --- a/tests/unit/test_unwinder.c +++ b/tests/unit/test_unwinder.c @@ -7,6 +7,10 @@ # include "unwinder/sentry_unwinder.h" # include # include +# if defined(__arm__) +# define UNW_LOCAL_ONLY +# include +# endif extern bool find_mem_range_from_fd(int fd, uintptr_t ptr, mem_range_t *range); #endif @@ -103,6 +107,29 @@ SENTRY_TEST(unwinder) } } +SENTRY_TEST(unwinder_unmapped_ip) +{ +#if !defined(SENTRY_WITH_UNWINDER_LIBUNWIND) || !defined(__arm__) + SKIP_TEST(); +#else + int stack_var = 0; + // libunwind uses its own register-array context on ARM. + unw_context_t unwind_context = { 0 }; + unwind_context.regs[13] = (uintptr_t)&stack_var; + unwind_context.regs[15] = 0x10c; + + sentry_ucontext_t context = { 0 }; + context.user_context = (ucontext_t *)&unwind_context; + + void *backtrace[2] = { 0 }; + size_t frame_count + = sentry_unwind_stack_from_ucontext(&context, backtrace, 2); + + TEST_CHECK_INT_EQUAL(frame_count, 1); + TEST_CHECK_PTR_EQUAL(backtrace[0], (void *)(uintptr_t)0x10c); +#endif +} + SENTRY_TEST(find_mem_range) { #if !defined(SENTRY_WITH_UNWINDER_LIBUNWIND) diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index 0ac0b78a05..12d5dd5b9e 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -430,6 +430,7 @@ XX(uint128_struct_size) XX(uninitialized) XX(unsampled_spans) XX(unwinder) +XX(unwinder_unmapped_ip) XX(update_from_header_no_sampled_flag) XX(update_from_header_null_ctx) XX(update_release_and_environment_late)