Index: lib/sanitizer_common/sanitizer_stacktrace.cc =================================================================== --- lib/sanitizer_common/sanitizer_stacktrace.cc +++ lib/sanitizer_common/sanitizer_stacktrace.cc @@ -36,19 +36,39 @@ return GET_CALLER_PC(); } +// Check if given pointer points into allocated stack area. +static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) { + return frame > stack_bottom && frame < stack_top - 2; +} + +// In GCC on ARM bp points to saved lr, not fp, so we should check the next +// cell in stack to be a saved frame pointer. GetCanonicFrame returns the +// pointer to saved frame pointer in any case. +static uhwptr *GetCanonicFrame(uptr bp, uptr stack_top, uptr stack_bottom) { + if (!IsValidFrame(bp, stack_top, stack_bottom)) + return 0; + uhwptr *bp_prev = (uhwptr *)bp; +#ifdef __arm__ + if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) + return bp_prev; + --bp_prev; +#endif + return bp_prev; +} + void StackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom, uptr max_depth) { CHECK_GE(max_depth, 2); trace[0] = pc; size = 1; - uhwptr *frame = (uhwptr *)bp; - uhwptr *prev_frame = frame - 1; + stack_bottom = Max(stack_bottom, (uptr)&size); + uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom); + uhwptr *prev_frame = 0; if (stack_top < 4096) return; // Sanity check for stack top. // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. while (frame > prev_frame && - frame < (uhwptr *)stack_top - 2 && - frame > (uhwptr *)stack_bottom && + IsValidFrame((uptr)frame, stack_top, stack_bottom) && IsAligned((uptr)frame, sizeof(*frame)) && size < max_depth) { uhwptr pc1 = frame[1]; @@ -56,7 +76,7 @@ trace[size++] = (uptr) pc1; } prev_frame = frame; - frame = (uhwptr *)frame[0]; + frame = GetCanonicFrame((uptr)frame[0], stack_top, stack_bottom); } } Index: test/asan/TestCases/Linux/clang_gcc_abi.cc =================================================================== --- test/asan/TestCases/Linux/clang_gcc_abi.cc +++ test/asan/TestCases/Linux/clang_gcc_abi.cc @@ -0,0 +1,43 @@ +// RUN: %clangxx_asan -O0 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s + +// REQUIRES: arm-supported-target + +#include + +int boom() { + volatile int three = 3; + char *s = (char *)malloc(three); + return s[three]; //BOOM +} + +__attribute__((naked, noinline)) void gcc_abi() { + asm volatile("str fp, [sp, #-8]!\n\t" + "str lr, [sp, #4]\n\t" + "add fp, sp, #4\n\t" + "bl boom\n\t" + "sub sp, fp, #4\n\t" + "ldr fp, [sp]\n\t" + "add sp, sp, #4\n\t" + "ldr pc, [sp], #4\n\t" + ); +} + +__attribute__((naked, noinline)) void clang_abi() { + asm volatile("push {r11, lr}\n\t" + "mov r11, sp\n\t" + "bl gcc_abi\n\t" + "add r0, r0, #1\n\t" + "pop {r11, pc}\n\t" + ); +} + +int main() { + clang_abi(); +} +// CHECK: #1 0x{{.*}} in boom {{.*}}clang_gcc_abi.cc:[[@LINE-28]] +// CHECK: #2 0x{{.*}} in gcc_abi {{.*}}clang_gcc_abi.cc:[[@LINE-24]] +// CHECK: #3 0x{{.*}} in clang_abi {{.*}}clang_gcc_abi.cc:[[@LINE-13]] +// CHECK: #4 0x{{.*}} in main {{.*}}clang_gcc_abi.cc:[[@LINE-5]]