LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 20800 - Invalid compact unwind info generated for a function without frame pointers on OSX
Summary: Invalid compact unwind info generated for a function without frame pointers o...
Status: RESOLVED FIXED
Alias: None
Product: libraries
Classification: Unclassified
Component: Backend: X86 (show other bugs)
Version: trunk
Hardware: PC MacOS X
: P normal
Assignee: Alexander Potapenko
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-08-29 04:53 PDT by Alexander Potapenko
Modified: 2014-09-09 09:51 PDT (History)
6 users (show)

See Also:
Fixed By Commit(s):


Attachments
test case for which the incorrect debug info is generated (1.84 KB, application/octet-stream)
2014-08-29 04:54 PDT, Alexander Potapenko
Details
Patch that makes Clang generate correct unwind info for the ASan runtime. (1.61 KB, patch)
2014-08-29 09:23 PDT, Alexander Potapenko
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Alexander Potapenko 2014-08-29 04:53:44 PDT
The attached file contains the __asan_report_error function for which the compact unwind info appears to be incorrect if the frame pointers are omitted:

$ bin/clang++   -O3   -fomit-frame-pointer asan_report.ii -c
$ bin/llvm-objdump -unwind-info -d asan_report.o
...
__Z19__asan_report_errormmmm:
       0:       55                                              pushq   %rbp
       1:       41 57                                           pushq   %r15
       3:       41 56                                           pushq   %r14
       5:       41 55                                           pushq   %r13
       7:       41 54                                           pushq   %r12
       9:       53                                              pushq   %rbx
       a:       48 81 ec 18 08 00 00                            subq    $2072, %rsp
...
Contents of __compact_unwind section:
  Entry at offset 0x0:
    start:                0x0 __Z19__asan_report_errormmmm
    length:               0xda
    compact encoding:     0x0309f800

According to /usr/include/mach-o/compact_unwind_encoding.h, the compact encoding uses the frameless stack index mode (0x03000000 is UNWIND_X86_64_MODE_STACK_IND), so the second byte of the compact encoding must be the offset of the immediate constant denoting the stack size in the subq instruction. This byte has value 0x9 instead of 0xc, which makes the unwinder think the function stack size is around 3Gb.

This test case contains a reduced version of __asan_report_error in the ASan runtime. I'm seeing actual crashes because of this bug when calling _Unwind_Backtrace from the real __asan_report_error on OSX. GDB also has problems unwinding through this function on OSX.
A number of other functions in the ASan runtime have the same incorrect compact unwind info.
Comment 1 Alexander Potapenko 2014-08-29 04:54:43 PDT
Created attachment 12952 [details]
test case for which the incorrect debug info is generated
Comment 2 Alexander Potapenko 2014-08-29 05:25:46 PDT
Looks like Target/X86/MCTargetDesc/X86AsmBackend.cpp assumes that the size of a push instruction is always constant on X86.
However it may vary: in the objdump above the push instruction sizes for RBP and RBX are equal to 1, while the sizes for R12-R15 are 2.
As a result, the offset is off by 4.
Comment 3 Alexander Potapenko 2014-08-29 09:23:44 PDT
Created attachment 12953 [details]
Patch that makes Clang generate correct unwind info for the ASan runtime.
Comment 4 Alexander Potapenko 2014-09-01 06:26:16 PDT
I also think it's reasonable to add a check to CompactUnwinder.hpp in libcxxabi so that it doesn't crash on unexpectedly big stack sizes. Nick, what do you think?
Comment 5 Nick Kledzik 2014-09-02 13:34:42 PDT
If we added a check to the unwinder, all it could do is assert() which is itself a form of crashing.  We need to catch this way earlier.

When the compact unwind creation code lived in the linker, for UNWIND_MOD_STACK_IND it would check the actual bytes in the function instruction to make sure the stack size value needed was at the offset being computed.  Is there a way to pass the function bytes down into generateCompactUnwindEncoding() so that check could be done?
Comment 6 Alexander Potapenko 2014-09-03 02:19:43 PDT
> If we added a check to the unwinder, all it could do is assert() which is itself a form of crashing.  We need to catch this way earlier.
We could just bail out from the unwinding procedure returning some reason code, but not crashing the whole program.

This can be just a stopgap measure that'll fix the situation for libcxxabi users until the bug is fixed in the system compiler.
Comment 7 Alexander Potapenko 2014-09-09 02:02:38 PDT
Fixed in r217020 and r217021
Comment 8 Sanjay Patel 2014-09-09 09:51:46 PDT
Hi Alexander -

Your switch doesn't include cases for r8 - r11 (which would be 2 byte push instructions). I assume that's because they are not callee saved registers? A comment in the code to make that obvious would be good (or just handle those cases anyway).

Is there no general-purpose way to determine an instruction's size at this level?