Fast unwind works wrong in GCC 4.10 on ARM Linux due to FP format mismatch between libsanitizer and GCC. This is related bug in GCC (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61771).
Diff Detail
Event Timeline
Can we add tests?
Evgeniy suggests that a test may be implemented with a set of assembly files that have different ABIs (GCC's and Clang's)
I agree with tests, no regressions on current tests don't mean much.
cheers,
--renato
lib/sanitizer_common/sanitizer_stacktrace.cc | ||
---|---|---|
53 | It's not clear how this will separate a GCC logic from LLVM one (or rather, different FP logics), on ARM. It'll also make the second IsValidFrame() call redundant on anything _but_ ARM. Maybe you should move all of it inside the #ifdef block? #ifdef __arm__ if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) return bp_prev; --bp_prev; #endif return bp_prev; |
Thanks, Renato, you are right, I've also added a small test. Should I add more tests?
lib/sanitizer_common/sanitizer_stacktrace.cc | ||
---|---|---|
40 | this function returns bool | |
65–66 | This line is wrong. It assumes that FastUnwindStack() is called in the same thread for which we provide stack_top/stack_bottom. I believe this function describes a generic unwinding algorithm, and there's no place for hack like this here. Why do you need it? |
lib/sanitizer_common/sanitizer_stacktrace.cc | ||
---|---|---|
65–66 | Hm, stack_bottom is simply stack_top - kStackSize (8 MB), isn't it? So, we have 8 MB interval for "valid" stack addresses. But in Linux stack grows dynamically, so if access address is, for example, in the middle of this interval, this can cause a segmentation fault, because libc hasn't mapped this memory yet. So we need something like this to prevent this error. You are right, this will work only in case if FastUnwindStack() is called in the same thread for which we provide stack_top/stack_bottom, but if it is called in another thread, how can we implement such kind of protection? |
lib/sanitizer_common/sanitizer_stacktrace.cc | ||
---|---|---|
65–66 | Can we do stack_bottom = Max(stack_bottom, bp) instead? |
Updated patch according to Renato's and Yury's comments. Regarding the issue about stack_bottom, I still believe that we need something like the protection was suggested.
lib/sanitizer_common/sanitizer_stacktrace.cc | ||
---|---|---|
41 | Should this be 2 * sizeof(uhwptr)? |
lib/sanitizer_common/sanitizer_stacktrace.cc | ||
---|---|---|
65–66 | Stack size is not always 8Mb, it's configurable in many ways. And, yes, it grows dynamically. But we don't assume that the whole interval from stack_top to stack_bottom is accessible. We would access unmapped memory only if there's a bug in unwinding algorithm or the frame pointers are broken. Do you actually observe such cases? |
lib/sanitizer_common/sanitizer_stacktrace.cc | ||
---|---|---|
65–66 | We could also access unmapped area if code was compiled without fp support. And yes, we saw this in our ARM tests. |
Alexey, you are right, this is a really specific situation. Removed the line. Is it OK now?
lib/sanitizer_common/sanitizer_stacktrace.cc | ||
---|---|---|
47 | Make this inline. | |
48 | This check is not needed if we're not on ARM. Can you keep the original behavior on non-ARM platforms? #ifdef __arm__ if (!IsValidFrame(bp, stack_top, stack_bottom) return 0; uhwptr *bp_prev = (uhwptr *)bp; if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom) return bp_prev; return bp_prev - 1; #else return (uhwptr*)bp; #endif | |
66–68 | Move this line upper (before calling GetCanonicFrame for the first time). | |
test/asan/TestCases/Linux/clang_gcc_abi.cc | ||
41 | Put CHECK-lines closer to the actual source code lines |
Looks reasonable. Please fix the test case and let me know if I should land this for you.
test/asan/TestCases/Linux/clang_gcc_abi.cc | ||
---|---|---|
15 | [[@LINE]] directives don't look right now. |
test/asan/TestCases/Linux/clang_gcc_abi.cc | ||
---|---|---|
15 | Yes, it does. ================================================================= ==12410==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x422007f3 at pc 0x000c1444 bp 0x40800118 sp 0x40800110 READ of size 1 at 0x422007f3 thread T0 #0 0xc1443 in boom /home/max/workspace/downloads/llvm/projects/compiler-rt/test/asan/TestCases/Linux/clang_gcc_abi.cc:13:3 #1 0xc1453 in gcc_abi /home/max/workspace/downloads/llvm/projects/compiler-rt/test/asan/TestCases/Linux/clang_gcc_abi.cc:19:3 #2 0xc1453 in gcc_abi /home/max/workspace/downloads/llvm/projects/compiler-rt/test/asan/TestCases/Linux/clang_gcc_abi.cc:19:3 #3 0xc1453 in gcc_abi /home/max/workspace/downloads/llvm/projects/compiler-rt/test/asan/TestCases/Linux/clang_gcc_abi.cc:19:3 SUMMARY: AddressSanitizer: heap-buffer-overflow /home/max/workspace/downloads/llvm/projects/compiler-rt/test/asan/TestCases/Linux/clang_gcc_abi.cc:13 boom However, ASan unable to unwind the stack deeper then gcc_abi function. Should I do something about it? |
test/asan/TestCases/Linux/clang_gcc_abi.cc | ||
---|---|---|
15 | That's expected - your inline asm lacks frame info so assembler can't generate proper unwind instructions which puzzles slow unwinder. |
this function returns bool