This is an archive of the discontinued LLVM Phabricator instance.

[lld-macho] Check if DWARF offset is too large for compact unwind
ClosedPublic

Authored by int3 on Apr 3 2023, 11:32 PM.

Details

Summary

For functions that use DWARF encodings, their compact unwind entry will
contain a hint about the offset of their DWARF entry from the start of
the __eh_frame section. The encoding only has 3 bytes to encode this
hint.

Previously, I neglected to check for overflow (and didn't realize that
the value was merely a hint without needing to be exact.) So for large
__eh_frame sections, the hint would overflow and cause the compact
unwind MODE flag to be corrupted, leading to uncaught exceptions at
runtime.

This diff fixes things by encoding zero as the hint for offsets that are
too large. The unwinder will start a linear search at the hint location
for the matching CFI record. The only requirement is that the hint
points to a valid CFI record start, and the start of the section is
always the start of a CFI record (in well-formed programs).

I'm not adding a test for this because generating the test inputs takes
a bit too much time. However, I have been testing locally with this lit
file, which takes about 15s to run on my machine:

# RUN: rm -rf %t; mkdir %t
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos11.0 %s -o %t/test.o
# RUN: %lld -dylib -lSystem %t/test.o -o %t/test

.subsections_via_symbols
.text
.p2align 2

_f:
  .cfi_startproc
.rept 0x7fffff
  .cfi_escape 0x2e, 0x10
.endr
  ret
  .cfi_endproc

_g:
  .cfi_startproc
  .cfi_escape 0x2e, 0x10
  ret
  .cfi_endproc

Diff Detail

Event Timeline

int3 created this revision.Apr 3 2023, 11:32 PM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptApr 3 2023, 11:32 PM
Herald added a reviewer: Restricted Project. · View Herald Transcript
int3 requested review of this revision.Apr 3 2023, 11:32 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 3 2023, 11:32 PM
smeenai accepted this revision.Apr 3 2023, 11:53 PM
smeenai added a subscriber: smeenai.

For the test, would it work to put something like

.section __TEXT,__eh_frame
.space 0x1000000

at the start of the file, to push the actual DWARF entry offsets forward?

This revision is now accepted and ready to land.Apr 3 2023, 11:53 PM
int3 added a comment.Apr 4 2023, 5:57 AM

I think both linkers expect the EH frame section to be a contiguous array of CFI entries. Using the .space 1000 thing causes ld64 to crash and LLD to silently drop all subsequent EH frames

int3 added inline comments.Apr 4 2023, 6:19 AM
lld/MachO/UnwindInfoSection.cpp
351

Upon closer inspection I think this only works if the hint points to a valid CFI record start, otherwise the unwinder will just repeatedly fail to parse all CFI entries until the end of the section, then start again from the beginning. So I'm going to encode a zero instead.

I would like to eventually figure out how to build and test against a custom copy of libunwind to verify, but I'd like to get this fix out first. I believe emitting a zero here is safe.

int3 updated this revision to Diff 510776.Apr 4 2023, 6:24 AM
int3 edited the summary of this revision. (Show Details)

update

int3 edited the summary of this revision. (Show Details)Apr 4 2023, 6:25 AM
This revision was landed with ongoing or failed builds.Apr 4 2023, 6:30 AM
This revision was automatically updated to reflect the committed changes.