[PATCH] D147505: [lld-macho] Check if DWARF offset is too large for compact unwind

Jez Ng via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 3 23:32:37 PDT 2023


int3 created this revision.
Herald added projects: lld-macho, All.
Herald added a reviewer: lld-macho.
int3 requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

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 `0xffffff` as the hint for offsets
that are too large. The unwinder appears to do a linear search from the
hint location, so this should be optimal.

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:

  .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


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D147505

Files:
  lld/MachO/UnwindInfoSection.cpp


Index: lld/MachO/UnwindInfoSection.cpp
===================================================================
--- lld/MachO/UnwindInfoSection.cpp
+++ lld/MachO/UnwindInfoSection.cpp
@@ -51,6 +51,13 @@
 #define COMPRESSED_ENTRY_FUNC_OFFSET_MASK                                      \
   UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(~0)
 
+static_assert(static_cast<uint32_t>(UNWIND_X86_64_DWARF_SECTION_OFFSET) ==
+                  static_cast<uint32_t>(UNWIND_ARM64_DWARF_SECTION_OFFSET) &&
+              static_cast<uint32_t>(UNWIND_X86_64_DWARF_SECTION_OFFSET) ==
+                  static_cast<uint32_t>(UNWIND_X86_DWARF_SECTION_OFFSET));
+
+constexpr uint64_t DWARF_SECTION_OFFSET = UNWIND_X86_64_DWARF_SECTION_OFFSET;
+
 // Compact Unwind format is a Mach-O evolution of DWARF Unwind that
 // optimizes space and exception-time lookup.  Most DWARF unwind
 // entries can be replaced with Compact Unwind entries, but the ones
@@ -338,7 +345,13 @@
 
     // If we have DWARF unwind info, create a CU entry that points to it.
     if (d->unwindEntry->getName() == section_names::ehFrame) {
-      cu.encoding = target->modeDwarfEncoding | d->unwindEntry->outSecOff;
+      // The unwinder will look for the DWARF entry starting at the hint. If it
+      // fails to find the entry, it will proceed with a linear search starting
+      // from the hint offset until the end of the section. So if the offset is
+      // too large to be encoded, we simply encode the maximum possible value.
+      uint64_t dwarfOffsetHint =
+          std::min(d->unwindEntry->outSecOff, DWARF_SECTION_OFFSET);
+      cu.encoding = target->modeDwarfEncoding | dwarfOffsetHint;
       const FDE &fde = cast<ObjFile>(d->getFile())->fdes[d->unwindEntry];
       cu.functionLength = fde.funcLength;
       cu.personality = fde.personality;


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D147505.510704.patch
Type: text/x-patch
Size: 1815 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20230404/1d98afb5/attachment.bin>


More information about the llvm-commits mailing list