[ELF] - Remove unused synthetic sections correctly.
authorGeorge Rimar <grimar@accesssoftek.com>
Wed, 7 Feb 2018 09:11:07 +0000 (09:11 +0000)
committerGeorge Rimar <grimar@accesssoftek.com>
Wed, 7 Feb 2018 09:11:07 +0000 (09:11 +0000)
This is PR35740 which now crashes
because we remove unused synthetic sections incorrectly.

We can keep input section description and corresponding output
section live even if it must be empty and dead.
This results in a crash because SHF_LINK_ORDER handling code
tries to access first section which is nullptr in this case.

Patch fixes the issue.

Differential revision: https://reviews.llvm.org/D42681

llvm-svn: 324463

lld/ELF/Writer.cpp
lld/test/ELF/linkerscript/unused-synthetic.s
lld/test/ELF/linkerscript/unused-synthetic2.s [new file with mode: 0644]

index eddf1741436a34cdf467f2cca44c69f16d59fca7..9de734a1c0d475df843db625481a5279a3662a10 100644 (file)
@@ -1346,23 +1346,21 @@ static void removeUnusedSyntheticSections() {
     if (!OS || !SS->empty())
       continue;
 
-    std::vector<BaseCommand *>::iterator Empty = OS->SectionCommands.end();
-    for (auto I = OS->SectionCommands.begin(), E = OS->SectionCommands.end();
-         I != E; ++I) {
-      BaseCommand *B = *I;
-      if (auto *ISD = dyn_cast<InputSectionDescription>(B)) {
+    // If we reach here, then SS is an unused synthetic section and we want to
+    // remove it from corresponding input section description of output section.
+    for (BaseCommand *B : OS->SectionCommands)
+      if (auto *ISD = dyn_cast<InputSectionDescription>(B))
         llvm::erase_if(ISD->Sections,
                        [=](InputSection *IS) { return IS == SS; });
-        if (ISD->Sections.empty())
-          Empty = I;
-      }
-    }
-    if (Empty != OS->SectionCommands.end())
-      OS->SectionCommands.erase(Empty);
 
-    // If there are no other sections in the output section, remove it from the
-    // output.
-    if (OS->SectionCommands.empty())
+    // If there are no other alive sections or commands left in the output
+    // section description, we remove it from the output.
+    bool IsEmpty = llvm::all_of(OS->SectionCommands, [](BaseCommand *B) {
+      if (auto *ISD = dyn_cast<InputSectionDescription>(B))
+        return ISD->Sections.empty();
+      return false;
+    });
+    if (IsEmpty)
       OS->Live = false;
   }
 }
index b7cedbc8e09cbb63b7046814bff05494506239a8..fb334213aa6fbb6a2a36b3f4085ba255b6d9ad78 100644 (file)
@@ -1,7 +1,7 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
 # RUN: echo "SECTIONS { \
-# RUN:    .got  : { *(.got) } \
+# RUN:    .got  : { *(.got) *(.got) } \
 # RUN:    .plt  : { *(.plt) } \
 # RUN:    .text : { *(.text) } \
 # RUN:  }" > %t.script
diff --git a/lld/test/ELF/linkerscript/unused-synthetic2.s b/lld/test/ELF/linkerscript/unused-synthetic2.s
new file mode 100644 (file)
index 0000000..37ebc50
--- /dev/null
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=armv7-unknown-linux-gnueabi %s -o %t.o
+# RUN: echo "SECTIONS { .trap : { *(.ARM.exidx) *(.dummy) } }" > %t.script
+
+## We incorrectly removed unused synthetic sections and crashed before.
+## Check we do not crash and do not produce .trap output section.
+# RUN: ld.lld -shared -o %t.so --script %t.script %t.o
+# RUN: llvm-objdump -section-headers %t.so | FileCheck %s
+# CHECK-NOT: .trap