[llvm] 37ef743 - [MC] [Win64EH] Avoid producing malformed xdata records

Martin Storsjö via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 27 23:24:48 PDT 2020


Author: Martin Storsjö
Date: 2020-08-28T09:05:36+03:00
New Revision: 37ef743cbf3fb1c56cca8035d9acb0cde83976f9

URL: https://github.com/llvm/llvm-project/commit/37ef743cbf3fb1c56cca8035d9acb0cde83976f9
DIFF: https://github.com/llvm/llvm-project/commit/37ef743cbf3fb1c56cca8035d9acb0cde83976f9.diff

LOG: [MC] [Win64EH] Avoid producing malformed xdata records

If there's no unwinding opcodes, omit writing the xdata/pdata records.

Previously, this generated truncated xdata records, and llvm-readobj
would error out when trying to print them.

If writing of an xdata record is forced via the .seh_handlerdata
directive, skip it if there's no info to make a sensible unwind
info structure out of, and clearly error out if such info appeared
later in the process.

Differential Revision: https://reviews.llvm.org/D86527

Added: 
    

Modified: 
    llvm/include/llvm/MC/MCWinEH.h
    llvm/lib/MC/MCWin64EH.cpp
    llvm/test/MC/AArch64/seh.s

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/MC/MCWinEH.h b/llvm/include/llvm/MC/MCWinEH.h
index b1c28c0ecae7..baeafa3468e2 100644
--- a/llvm/include/llvm/MC/MCWinEH.h
+++ b/llvm/include/llvm/MC/MCWinEH.h
@@ -40,6 +40,7 @@ struct FrameInfo {
 
   bool HandlesUnwind = false;
   bool HandlesExceptions = false;
+  bool EmitAttempted = false;
 
   int LastFrameInst = -1;
   const FrameInfo *ChainedParent = nullptr;
@@ -53,6 +54,15 @@ struct FrameInfo {
             const FrameInfo *ChainedParent)
       : Begin(BeginFuncEHLabel), Function(Function),
         ChainedParent(ChainedParent) {}
+
+  bool empty() const {
+    if (!Instructions.empty())
+      return false;
+    for (const auto &E : EpilogMap)
+      if (!E.second.empty())
+        return false;
+    return true;
+  }
 };
 
 class UnwindEmitter {

diff  --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp
index ac288ca08c93..76c82cd176a1 100644
--- a/llvm/lib/MC/MCWin64EH.cpp
+++ b/llvm/lib/MC/MCWin64EH.cpp
@@ -494,6 +494,27 @@ static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
   // If this UNWIND_INFO already has a symbol, it's already been emitted.
   if (info->Symbol)
     return;
+  // If there's no unwind info here (not even a terminating UOP_End), the
+  // unwind info is considered bogus and skipped. If this was done in
+  // response to an explicit .seh_handlerdata, the associated trailing
+  // handler data is left orphaned in the xdata section.
+  if (info->empty()) {
+    info->EmitAttempted = true;
+    return;
+  }
+  if (info->EmitAttempted) {
+    // If we tried to emit unwind info before (due to an explicit
+    // .seh_handlerdata directive), but skipped it (because there was no
+    // valid information to emit at the time), and it later got valid unwind
+    // opcodes, we can't emit it here, because the trailing handler data
+    // was already emitted elsewhere in the xdata section.
+    streamer.getContext().reportError(
+        SMLoc(), "Earlier .seh_handlerdata for " + info->Function->getName() +
+                     " skipped due to no unwind info at the time "
+                     "(.seh_handlerdata too early?), but the function later "
+                     "did get unwind info that can't be emitted");
+    return;
+  }
 
   MCContext &context = streamer.getContext();
   MCSymbol *Label = context.createTempSymbol();
@@ -657,16 +678,25 @@ static void ARM64EmitRuntimeFunction(MCStreamer &streamer,
 void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer &Streamer) const {
   // Emit the unwind info structs first.
   for (const auto &CFI : Streamer.getWinFrameInfos()) {
+    WinEH::FrameInfo *Info = CFI.get();
+    if (Info->empty())
+      continue;
     MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
     Streamer.SwitchSection(XData);
-    ARM64EmitUnwindInfo(Streamer, CFI.get());
+    ARM64EmitUnwindInfo(Streamer, Info);
   }
 
   // Now emit RUNTIME_FUNCTION entries.
   for (const auto &CFI : Streamer.getWinFrameInfos()) {
+    WinEH::FrameInfo *Info = CFI.get();
+    // ARM64EmitUnwindInfo above clears the info struct, so we can't check
+    // empty here. But if a Symbol is set, we should create the corresponding
+    // pdata entry.
+    if (!Info->Symbol)
+      continue;
     MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
     Streamer.SwitchSection(PData);
-    ARM64EmitRuntimeFunction(Streamer, CFI.get());
+    ARM64EmitRuntimeFunction(Streamer, Info);
   }
 }
 

diff  --git a/llvm/test/MC/AArch64/seh.s b/llvm/test/MC/AArch64/seh.s
index 2f4e3f27255f..878b7ad944cf 100644
--- a/llvm/test/MC/AArch64/seh.s
+++ b/llvm/test/MC/AArch64/seh.s
@@ -1,6 +1,8 @@
 // This test checks that the SEH directives don't cause the assembler to fail.
+// Checking that llvm-readobj doesn't bail out on the unwind data, but not
+// really checking the contents yet.
 
-// RUN: llvm-mc -triple aarch64-pc-win32 -filetype=obj %s | llvm-readobj -S -r - | FileCheck %s
+// RUN: llvm-mc -triple aarch64-pc-win32 -filetype=obj %s | llvm-readobj -S -r -u - | FileCheck %s
 
 // CHECK:      Sections [
 // CHECK:        Section {
@@ -25,7 +27,7 @@
 // CHECK-NEXT:   }
 // CHECK:        Section {
 // CHECK:          Name: .pdata
-// CHECK:          RelocationCount: 4
+// CHECK:          RelocationCount: 2
 // CHECK:          Characteristics [
 // CHECK-NEXT:       ALIGN_4BYTES
 // CHECK-NEXT:       CNT_INITIALIZED_DATA
@@ -41,8 +43,6 @@
 // CHECK-NEXT:   Section (5) .pdata {
 // CHECK-NEXT:     0x0 IMAGE_REL_ARM64_ADDR32NB func
 // CHECK-NEXT:     0x4 IMAGE_REL_ARM64_ADDR32NB .xdata
-// CHECK-NEXT:     0x8 IMAGE_REL_ARM64_ADDR32NB smallFunc
-// CHECK-NEXT:     0xC IMAGE_REL_ARM64_ADDR32NB .xdata
 // CHECK-NEXT:   }
 // CHECK-NEXT: ]
 
@@ -67,7 +67,8 @@ func:
     ret
     .seh_endproc
 
-// Test emission of small functions.
+    // Function with no .seh directives; no pdata/xdata entries are
+    // generated.
     .globl smallFunc
     .def smallFunc
     .scl 2
@@ -77,3 +78,21 @@ func:
 smallFunc:
     ret
     .seh_endproc
+
+    // Function with no .seh directives, but with .seh_handlerdata.
+    // No xdata/pdata entries are generated, but the custom handler data
+    // (the .long after .seh_handlerdata) is left orphaned in the xdata
+    // section.
+    .globl handlerFunc
+    .def handlerFunc
+    .scl 2
+    .type 32
+    .endef
+    .seh_proc handlerFunc
+handlerFunc:
+    ret
+    .seh_handler __C_specific_handler, @except
+    .seh_handlerdata
+    .long 0
+    .text
+    .seh_endproc


        


More information about the llvm-commits mailing list