[llvm] 45b8a74 - [LLD][COFF] When using LLD-as-a-library, always prevent re-entrance on failures

Alexandre Ganea via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 12 05:14:55 PST 2020


Author: Alexandre Ganea
Date: 2020-11-12T08:14:43-05:00
New Revision: 45b8a741fbbf271e0fb71294cb7cdce3ad4b9bf3

URL: https://github.com/llvm/llvm-project/commit/45b8a741fbbf271e0fb71294cb7cdce3ad4b9bf3
DIFF: https://github.com/llvm/llvm-project/commit/45b8a741fbbf271e0fb71294cb7cdce3ad4b9bf3.diff

LOG: [LLD][COFF] When using LLD-as-a-library, always prevent re-entrance on failures

This is a follow-up for D70378 (Cover usage of LLD as a library).

While debugging an intermittent failure on a bot, I recalled this scenario which
causes the issue:

1.When executing lld/test/ELF/invalid/symtab-sh-info.s L45, we reach
  lld::elf::Obj-File::ObjFile() which goes straight into its base ELFFileBase(),
  then ELFFileBase::init().
2.At that point fatal() is thrown in lld/ELF/InputFiles.cpp L381, leaving a
  half-initialized ObjFile instance.
3.We then end up in lld::exitLld() and since we are running with LLD_IN_TEST, we
  hapily restore the control flow to CrashRecoveryContext::RunSafely() then back
  in lld::safeLldMain().
4.Before this patch, we called errorHandler().reset() just after, and this
  attempted to reset the associated SpecificAlloc<ObjFile<ELF64LE>>. That tried
  to free the half-initialized ObjFile instance, and more precisely its
  ObjFile::dwarf member.

Sometimes that worked, sometimes it failed and was catched by the
CrashRecoveryContext. This scenario was the reason we called
errorHandler().reset() through a CrashRecoveryContext.

But in some rare cases, the above repro somehow corrupted the heap, creating a
stack overflow. When the CrashRecoveryContext's filter (that is,
__except (ExceptionFilter(GetExceptionInformation()))) tried to handle the
exception, it crashed again since the stack was exhausted -- and that took the
whole application down. That is the issue seen on the bot. Locally it happens
about 1 times out of 15.

Now this situation can happen anywhere in LLD. Since catching stack overflows is
not a reliable scenario ATM when using CrashRecoveryContext, we're now
preventing further re-entrance when such failures occur, by signaling
lld::SafeReturn::canRunAgain=false. When running with LLD_IN_TEST=2 (or above),
only one iteration will be executed, instead of two.

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

Added: 
    

Modified: 
    lld/Common/ErrorHandler.cpp
    lld/include/lld/Common/Driver.h
    lld/test/COFF/arm-thumb-branch20-error.s
    lld/test/COFF/comdat-selection.s
    lld/test/COFF/delayimports-error.test
    lld/test/COFF/driver-windows.test
    lld/test/COFF/driver.test
    lld/test/COFF/export-limit.s
    lld/test/COFF/failifmismatch.test
    lld/test/COFF/invalid-obj.test
    lld/test/COFF/invalid-section-number.test
    lld/test/COFF/linkenv.test
    lld/test/COFF/manifestinput-error.test
    lld/test/COFF/merge.test
    lld/test/COFF/pdata-arm64-bad.yaml
    lld/test/COFF/precomp-link.test
    lld/test/COFF/thin-archive.s
    lld/test/COFF/thunk-replace.s
    lld/tools/lld/lld.cpp
    llvm/include/llvm/Support/CrashRecoveryContext.h
    llvm/include/llvm/Support/Process.h
    llvm/lib/Support/CrashRecoveryContext.cpp
    llvm/lib/Support/Process.cpp

Removed: 
    


################################################################################
diff  --git a/lld/Common/ErrorHandler.cpp b/lld/Common/ErrorHandler.cpp
index 41122e8fb9fd..269a0f62ec65 100644
--- a/lld/Common/ErrorHandler.cpp
+++ b/lld/Common/ErrorHandler.cpp
@@ -64,6 +64,10 @@ void lld::exitLld(int val) {
   if (errorHandler().outputBuffer)
     errorHandler().outputBuffer->discard();
 
+  // Re-throw a possible signal or exception once/if it was catched by
+  // safeLldMain().
+  CrashRecoveryContext::throwIfCrash(val);
+
   // Dealloc/destroy ManagedStatic variables before calling _exit().
   // In an LTO build, allows us to get the output of -time-passes.
   // Ensures that the thread pool for the parallel algorithms is stopped to
@@ -76,7 +80,10 @@ void lld::exitLld(int val) {
     lld::outs().flush();
     lld::errs().flush();
   }
-  llvm::sys::Process::Exit(val);
+  // When running inside safeLldMain(), restore the control flow back to the
+  // CrashRecoveryContext. Otherwise simply use _exit(), meanning no cleanup,
+  // since we want to avoid further crashes on shutdown.
+  llvm::sys::Process::Exit(val, /*NoCleanup=*/true);
 }
 
 void lld::diagnosticHandler(const DiagnosticInfo &di) {

diff  --git a/lld/include/lld/Common/Driver.h b/lld/include/lld/Common/Driver.h
index 7a0ad4b364cc..eb5bc7b82b9b 100644
--- a/lld/include/lld/Common/Driver.h
+++ b/lld/include/lld/Common/Driver.h
@@ -21,7 +21,9 @@ struct SafeReturn {
 // Generic entry point when using LLD as a library, safe for re-entry, supports
 // crash recovery. Returns a general completion code and a boolean telling
 // whether it can be called again. In some cases, a crash could corrupt memory
-// and re-entry would not be possible anymore.
+// and re-entry would not be possible anymore. Use exitLld() in that case to
+// properly exit your application and avoid intermittent crashes on exit caused
+// by cleanup.
 SafeReturn safeLldMain(int argc, const char **argv, llvm::raw_ostream &stdoutOS,
                        llvm::raw_ostream &stderrOS);
 

diff  --git a/lld/test/COFF/arm-thumb-branch20-error.s b/lld/test/COFF/arm-thumb-branch20-error.s
index fbbc0d49d02b..6802a02fe970 100644
--- a/lld/test/COFF/arm-thumb-branch20-error.s
+++ b/lld/test/COFF/arm-thumb-branch20-error.s
@@ -1,6 +1,6 @@
 // REQUIRES: arm
 // RUN: llvm-mc -filetype=obj -triple=thumbv7a-windows-gnu %s -o %t.obj
-// RUN: not lld-link -entry:_start -subsystem:console %t.obj -out:%t.exe 2>&1 | FileCheck %s
+// RUN: env LLD_IN_TEST=1 not lld-link -entry:_start -subsystem:console %t.obj -out:%t.exe 2>&1 | FileCheck %s
  .syntax unified
  .globl _start
 _start:

diff  --git a/lld/test/COFF/comdat-selection.s b/lld/test/COFF/comdat-selection.s
index 988d9bd9516d..a20ee38d0c4a 100644
--- a/lld/test/COFF/comdat-selection.s
+++ b/lld/test/COFF/comdat-selection.s
@@ -32,11 +32,11 @@ symbol:
 # RUN: cp %t.same_size.obj %t.obj && lld-link /dll /noentry /nodefaultlib %t.same_size.obj %t.obj
 # RUN: cp %t.same_contents.obj %t.obj && lld-link /dll /noentry /nodefaultlib %t.same_contents.obj %t.obj
 # RUN: cp %t.largest.obj %t.obj && lld-link /dll /noentry /nodefaultlib %t.largest.obj %t.obj
-# RUN: cp %t.newest.obj %t.obj && not lld-link /dll /noentry /nodefaultlib %t.newest.obj %t.obj 2>&1 | FileCheck --check-prefix=NEWNEW %s
+# RUN: cp %t.newest.obj %t.obj && env LLD_IN_TEST=1 not lld-link /dll /noentry /nodefaultlib %t.newest.obj %t.obj 2>&1 | FileCheck --check-prefix=NEWNEW %s
 # NEWNEW: lld-link: error: unknown comdat type 7 for symbol
 
 # /force doesn't affect errors about unknown comdat types.
-# RUN: cp %t.newest.obj %t.obj && not lld-link /force /dll /noentry /nodefaultlib %t.newest.obj %t.obj 2>&1 | FileCheck --check-prefix=NEWNEWFORCE %s
+# RUN: cp %t.newest.obj %t.obj && env LLD_IN_TEST=1 not lld-link /force /dll /noentry /nodefaultlib %t.newest.obj %t.obj 2>&1 | FileCheck --check-prefix=NEWNEWFORCE %s
 # NEWNEWFORCE: lld-link: error: unknown comdat type 7 for symbol
 
 # Check that same_size, same_contents, largest do what they're supposed to.

diff  --git a/lld/test/COFF/delayimports-error.test b/lld/test/COFF/delayimports-error.test
index f630103d093f..cced9fb65e61 100644
--- a/lld/test/COFF/delayimports-error.test
+++ b/lld/test/COFF/delayimports-error.test
@@ -3,7 +3,8 @@
 # RUN: lld-link /out:%t.dir/foo.dll /dll %t1.obj /export:datasym,DATA /noentry
 
 # RUN: yaml2obj %s -o %t2.obj
-# RUN: not lld-link /out:%t.exe /entry:main %t2.obj %t.dir/foo.lib /delayload:foo.dll \
+# RUN: env LLD_IN_TEST=1 not lld-link /out:%t.exe /entry:main %t2.obj \
+# RUN:   %t.dir/foo.lib /delayload:foo.dll \
 # RUN:   /alternatename:__delayLoadHelper2=main /opt:noref >& %t.log
 # RUN: FileCheck %s < %t.log
 

diff  --git a/lld/test/COFF/driver-windows.test b/lld/test/COFF/driver-windows.test
index 1b93a53bddb3..407da16359bf 100644
--- a/lld/test/COFF/driver-windows.test
+++ b/lld/test/COFF/driver-windows.test
@@ -1,3 +1,3 @@
 # REQUIRES: system-windows
-# RUN: not LLD-LINK 2>&1 | FileCheck %s
+# RUN: env LLD_IN_TEST=1 not LLD-LINK 2>&1 | FileCheck %s
 CHECK: no input files

diff  --git a/lld/test/COFF/driver.test b/lld/test/COFF/driver.test
index 143d5f74fdba..d756dc9ed4aa 100644
--- a/lld/test/COFF/driver.test
+++ b/lld/test/COFF/driver.test
@@ -13,18 +13,18 @@ BADFILE: bad file type. Did you specify a DLL instead of an import library?
 # RUN: lld-link /lib /help | FileCheck -check-prefix=LIBHELP %s
 LIBHELP: OVERVIEW: LLVM Lib
 
-# RUN: not lld-link /WX /lib 2>&1 | FileCheck -check-prefix=LIBBAD %s
+# RUN: env LLD_IN_TEST=1 not lld-link /WX /lib 2>&1 | FileCheck -check-prefix=LIBBAD %s
 LIBBAD: ignoring /lib since it's not the first argument
 
 # RUN: yaml2obj %p/Inputs/hello32.yaml -o %t.obj
 # RUN: not lld-link /out:/ %t.obj 2>&1 | FileCheck -check-prefix=DIR %s
 DIR: cannot open output file
 
-# RUN: not lld-link -version 2>&1 | FileCheck -check-prefix=SPELLVERSION %s
+# RUN: env LLD_IN_TEST=1 not lld-link -version 2>&1 | FileCheck -check-prefix=SPELLVERSION %s
 SPELLVERSION: ignoring unknown argument '-version', did you mean '--version'
 SPELLVERSION: no input files
 
-# RUN: not lld-link -nodefaultlibs 2>&1 | FileCheck -check-prefix=SPELLNODEFAULTLIB %s
+# RUN: env LLD_IN_TEST=1 not lld-link -nodefaultlibs 2>&1 | FileCheck -check-prefix=SPELLNODEFAULTLIB %s
 SPELLNODEFAULTLIB: ignoring unknown argument '-nodefaultlibs', did you mean '-nodefaultlib'
 SPELLNODEFAULTLIB: no input files
 

diff  --git a/lld/test/COFF/export-limit.s b/lld/test/COFF/export-limit.s
index e65a84cb718f..8936754ab268 100644
--- a/lld/test/COFF/export-limit.s
+++ b/lld/test/COFF/export-limit.s
@@ -3,7 +3,7 @@
 # RUN: %python %p/Inputs/def-many.py 65536 > %t-65536.def
 # RUN: llvm-mc -triple x86_64-win32 %s -filetype=obj -o %t.obj
 # RUN: lld-link -dll -noentry %t.obj -out:%t.dll -def:%t-65535.def
-# RUN: not lld-link -dll -noentry %t.obj -out:%t.dll -def:%t-65536.def 2>&1 | FileCheck %s
+# RUN: env LLD_IN_TEST=1 not lld-link -dll -noentry %t.obj -out:%t.dll -def:%t-65536.def 2>&1 | FileCheck %s
 
 # CHECK: error: too many exported symbols
 

diff  --git a/lld/test/COFF/failifmismatch.test b/lld/test/COFF/failifmismatch.test
index 1cf77e47b035..25ca1012dc0d 100644
--- a/lld/test/COFF/failifmismatch.test
+++ b/lld/test/COFF/failifmismatch.test
@@ -9,15 +9,15 @@ RUN:   %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k2=v1
 RUN: lld-link /entry:main /subsystem:console /out:%t.exe \
 RUN:   %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v1
 
-RUN: not lld-link /entry:main /subsystem:console /out:%t.exe \
+RUN: env LLD_IN_TEST=1 not lld-link /entry:main /subsystem:console /out:%t.exe \
 RUN:   %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v2 2>&1 | FileCheck %s 
 
 RUN: llc < %p/Inputs/failmismatch1.ll -mtriple x86_64-windows-msvc -filetype obj -o %t1.obj
 RUN: llc < %p/Inputs/failmismatch2.ll -mtriple x86_64-windows-msvc -filetype obj -o %t2.obj
-RUN: not lld-link %t1.obj %t2.obj 2>&1 | FileCheck %s -check-prefix OBJ
+RUN: env LLD_IN_TEST=1 not lld-link %t1.obj %t2.obj 2>&1 | FileCheck %s -check-prefix OBJ
 
 RUN: llvm-lib %t1.obj /out:%t.lib
-RUN: not lld-link %t.lib %t2.obj 2>&1 | FileCheck %s -check-prefix LIB
+RUN: env LLD_IN_TEST=1 not lld-link %t.lib %t2.obj 2>&1 | FileCheck %s -check-prefix LIB
 
 CHECK: lld-link: error: /failifmismatch: mismatch detected for 'k1':
 CHECK-NEXT: >>> cmd-line has value v1

diff  --git a/lld/test/COFF/invalid-obj.test b/lld/test/COFF/invalid-obj.test
index d24daa48ddbf..078cd13dad13 100644
--- a/lld/test/COFF/invalid-obj.test
+++ b/lld/test/COFF/invalid-obj.test
@@ -1,5 +1,5 @@
 # RUN: yaml2obj %s -o %t.obj
-# RUN: not lld-link %t.obj 2>&1 | FileCheck %s
+# RUN: env LLD_IN_TEST=1 not lld-link %t.obj 2>&1 | FileCheck %s
 
 # CHECK: getSectionName failed: #1:
 

diff  --git a/lld/test/COFF/invalid-section-number.test b/lld/test/COFF/invalid-section-number.test
index 432d3549bb16..8860affaaa5c 100644
--- a/lld/test/COFF/invalid-section-number.test
+++ b/lld/test/COFF/invalid-section-number.test
@@ -1,5 +1,5 @@
 # RUN: yaml2obj %s -o %t.obj
-# RUN: not lld-link %t.obj 2>&1 | FileCheck %s
+# RUN: env LLD_IN_TEST=1 not lld-link %t.obj 2>&1 | FileCheck %s
 
 # CHECK: foo should not refer to special section -10
 

diff  --git a/lld/test/COFF/linkenv.test b/lld/test/COFF/linkenv.test
index 78d11fd5d0a8..752f39f12631 100644
--- a/lld/test/COFF/linkenv.test
+++ b/lld/test/COFF/linkenv.test
@@ -3,7 +3,7 @@
 
 CHECK: OVERVIEW: LLVM Linker
 
-# RUN: env LINK=-help not lld-link /lldignoreenv 2>&1 | \
+# RUN: env LLD_IN_TEST=1 LINK=-help not lld-link /lldignoreenv 2>&1 | \
 # RUN:     FileCheck --check-prefix=ERR %s
 
 ERR: error: no input files

diff  --git a/lld/test/COFF/manifestinput-error.test b/lld/test/COFF/manifestinput-error.test
index 9d47b9c9a79e..ea61bae2f7c0 100644
--- a/lld/test/COFF/manifestinput-error.test
+++ b/lld/test/COFF/manifestinput-error.test
@@ -2,7 +2,7 @@
 # UNSUPPORTED: libxml2
 
 # RUN: yaml2obj %p/Inputs/ret42.yaml -o %t.obj
-# RUN: not lld-link /out:%t.exe /entry:main \
+# RUN: env LLD_IN_TEST=1 not lld-link /out:%t.exe /entry:main \
 # RUN:   /manifest:embed \
 # RUN:   /manifestuac:"level='requireAdministrator'" \
 # RUN:   /manifestinput:%p/Inputs/manifestinput.test %t.obj 2>&1 | FileCheck %s

diff  --git a/lld/test/COFF/merge.test b/lld/test/COFF/merge.test
index af368407e7e8..11824aac1b08 100644
--- a/lld/test/COFF/merge.test
+++ b/lld/test/COFF/merge.test
@@ -7,17 +7,17 @@
 # RUN:   /merge:.foo=.bar /merge:.bar=.abc %t.obj /debug
 # RUN: llvm-readobj --sections %t.exe | FileCheck --check-prefix=CHECK2 %s
 
-# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: env LLD_IN_TEST=1 not lld-link /out:%t.exe /entry:main /subsystem:console /force \
 # RUN:   /merge:.rsrc=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RSRC %s
-# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: env LLD_IN_TEST=1 not lld-link /out:%t.exe /entry:main /subsystem:console /force \
 # RUN:   /merge:.foo=.rsrc %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RSRC %s
-# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: env LLD_IN_TEST=1 not lld-link /out:%t.exe /entry:main /subsystem:console /force \
 # RUN:   /merge:.reloc=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RELOC %s
-# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: env LLD_IN_TEST=1 not lld-link /out:%t.exe /entry:main /subsystem:console /force \
 # RUN:   /merge:.foo=.reloc %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RELOC %s
-# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: env LLD_IN_TEST=1 not lld-link /out:%t.exe /entry:main /subsystem:console /force \
 # RUN:   /merge:.foo=.foo1 /merge:.foo1=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-CYCLE %s
-# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: env LLD_IN_TEST=1 not lld-link /out:%t.exe /entry:main /subsystem:console /force \
 # RUN:   /merge:.foo=.foo1 /merge:.foo1=.foo2 /merge:.foo2=.foo1 %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-CYCLE %s
 
 # CHECK: Name: .def

diff  --git a/lld/test/COFF/pdata-arm64-bad.yaml b/lld/test/COFF/pdata-arm64-bad.yaml
index 8b43b66cc7ce..1314998aef90 100644
--- a/lld/test/COFF/pdata-arm64-bad.yaml
+++ b/lld/test/COFF/pdata-arm64-bad.yaml
@@ -1,5 +1,5 @@
 # RUN: yaml2obj %s -o %t.obj
-# RUN: not lld-link /out:%t.exe /entry:func1 /subsystem:console %t.obj 2>&1 | FileCheck %s
+# RUN: env LLD_IN_TEST=1 not lld-link /out:%t.exe /entry:func1 /subsystem:console %t.obj 2>&1 | FileCheck %s
 
 # This file is like pdata-arm64.yaml, except that .pdata has been extended with
 # 4 bytes. This can happen due to for example bad assembler input. Check that

diff  --git a/lld/test/COFF/precomp-link.test b/lld/test/COFF/precomp-link.test
index c9a5c605da8f..ee496c9bc946 100644
--- a/lld/test/COFF/precomp-link.test
+++ b/lld/test/COFF/precomp-link.test
@@ -33,9 +33,9 @@ RUN: sed 's/Signature: *545589255/Signature: 0/' < %t.precomp.yaml > precomp-zer
 RUN: yaml2obj precomp-no-objname.yaml -o %t.precomp-no-objname.obj
 RUN: yaml2obj precomp-zero-sig.yaml -o %t.precomp-zero-sig.obj
 
-RUN: not lld-link %t.precomp-no-objname.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe 2>&1 | FileCheck %s -check-prefix FAILURE-NO-SIGNATURE
+RUN: env LLD_IN_TEST=1 not lld-link %t.precomp-no-objname.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe 2>&1 | FileCheck %s -check-prefix FAILURE-NO-SIGNATURE
 
-RUN: not lld-link %t.precomp-zero-sig.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe 2>&1 | FileCheck %s -check-prefix FAILURE-NO-SIGNATURE
+RUN: env LLD_IN_TEST=1 not lld-link %t.precomp-zero-sig.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe 2>&1 | FileCheck %s -check-prefix FAILURE-NO-SIGNATURE
 
 FAILURE-NO-SIGNATURE: error: {{.*}}.obj claims to be a PCH object, but does not have a valid signature
 
@@ -43,7 +43,7 @@ Check that two PCH objs with duplicate signatures are an error.
 
 RUN: cp %S/Inputs/precomp.obj %t.precomp-dup.obj
 
-RUN: not lld-link %S/Inputs/precomp.obj %t.precomp-dup.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe 2>&1 | FileCheck %s -check-prefix FAILURE-DUP-SIGNATURE
+RUN: env LLD_IN_TEST=1 not lld-link %S/Inputs/precomp.obj %t.precomp-dup.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe 2>&1 | FileCheck %s -check-prefix FAILURE-DUP-SIGNATURE
 
 FAILURE-DUP-SIGNATURE: error: a PCH object with the same signature has already been provided ({{.*precomp.obj and .*precomp-dup.obj.*}})
 

diff  --git a/lld/test/COFF/thin-archive.s b/lld/test/COFF/thin-archive.s
index a1491cb7c4ab..a35eabed688c 100644
--- a/lld/test/COFF/thin-archive.s
+++ b/lld/test/COFF/thin-archive.s
@@ -17,9 +17,9 @@
 # RUN: rm %t.lib.obj
 # RUN: lld-link /entry:main %t.main.obj %t.lib /out:%t.exe 2>&1 | \
 # RUN:     FileCheck --allow-empty %s
-# RUN: not lld-link /entry:main %t.main.obj %t_thin.lib /out:%t.exe 2>&1 | \
-# RUN:     FileCheck --check-prefix=NOOBJ %s
-# RUN: not lld-link /entry:main %t.main.obj %t_thin.lib /out:%t.exe \
+# RUN: env LLD_IN_TEST=1 not lld-link /entry:main %t.main.obj %t_thin.lib \
+# RUN:     /out:%t.exe 2>&1 | FileCheck --check-prefix=NOOBJ %s
+# RUN: env LLD_IN_TEST=1 not lld-link /entry:main %t.main.obj %t_thin.lib /out:%t.exe \
 # RUN:     /demangle:no 2>&1 | FileCheck --check-prefix=NOOBJNODEMANGLE %s
 
 # CHECK-NOT: error: could not get the buffer for the member defining

diff  --git a/lld/test/COFF/thunk-replace.s b/lld/test/COFF/thunk-replace.s
index 2d47fcc64837..0b53f09ef048 100644
--- a/lld/test/COFF/thunk-replace.s
+++ b/lld/test/COFF/thunk-replace.s
@@ -3,7 +3,8 @@
 # RUN: llvm-mc -triple=x86_64-win32 %s -filetype=obj -o %t.main.obj
 # RUN: llvm-mc -triple=x86_64-win32 %p/Inputs/otherFunc.s -filetype=obj -o %t.other.obj
 # RUN: llvm-ar rcs %t.other.lib %t.other.obj
-# RUN: not lld-link -out:%t.exe -entry:main %t.main.obj %p/Inputs/std64.lib %t.other.lib -opt:noref 2>&1 | FileCheck %s
+# RUN: env LLD_IN_TEST=1 not lld-link -out:%t.exe -entry:main %t.main.obj \
+# RUN:     %p/Inputs/std64.lib %t.other.lib -opt:noref 2>&1 | FileCheck %s
 # CHECK: MessageBoxA was replaced
 
 .global main

diff  --git a/lld/tools/lld/lld.cpp b/lld/tools/lld/lld.cpp
index 48d5ae1a0ea0..5d71a8f24adf 100644
--- a/lld/tools/lld/lld.cpp
+++ b/lld/tools/lld/lld.cpp
@@ -179,7 +179,7 @@ SafeReturn lld::safeLldMain(int argc, const char **argv,
     if (!crc.RunSafely([&]() {
           r = lldMain(argc, argv, stdoutOS, stderrOS, /*exitEarly=*/false);
         }))
-      r = crc.RetCode;
+      return {crc.RetCode, /*canRunAgain=*/false};
   }
 
   // Cleanup memory and reset everything back in pristine condition. This path
@@ -221,7 +221,7 @@ int main(int argc, const char **argv) {
     // Execute one iteration.
     auto r = safeLldMain(argc, argv, llvm::outs(), llvm::errs());
     if (!r.canRunAgain)
-      _exit(r.ret); // Exit now, can't re-execute again.
+      exitLld(r.ret); // Exit now, can't re-execute again.
 
     if (!mainRet) {
       mainRet = r.ret;
@@ -230,14 +230,5 @@ int main(int argc, const char **argv) {
       return r.ret;
     }
   }
-#if LLVM_ON_UNIX
-  // Re-throw the signal so it can be caught by WIFSIGNALED in
-  // llvm/lib/Support/Unix/Program.inc. This is required to correctly handle
-  // usages of `not --crash`.
-  if (*mainRet > 128) {
-    llvm::sys::unregisterHandlers();
-    raise(*mainRet - 128);
-  }
-#endif
   return *mainRet;
 }

diff  --git a/llvm/include/llvm/Support/CrashRecoveryContext.h b/llvm/include/llvm/Support/CrashRecoveryContext.h
index 0fd1d4675c7c..f756635ee1f9 100644
--- a/llvm/include/llvm/Support/CrashRecoveryContext.h
+++ b/llvm/include/llvm/Support/CrashRecoveryContext.h
@@ -102,6 +102,10 @@ class CrashRecoveryContext {
   LLVM_ATTRIBUTE_NORETURN
   void HandleExit(int RetCode);
 
+  /// Throw again a signal or an exception, after it was catched once by a
+  /// CrashRecoveryContext.
+  static bool throwIfCrash(int RetCode);
+
   /// In case of a crash, this is the crash identifier.
   int RetCode = 0;
 

diff  --git a/llvm/include/llvm/Support/Process.h b/llvm/include/llvm/Support/Process.h
index af5091ab8ff4..729917bb41f4 100644
--- a/llvm/include/llvm/Support/Process.h
+++ b/llvm/include/llvm/Support/Process.h
@@ -213,8 +213,9 @@ class Process {
   /// Equivalent to ::exit(), except when running inside a CrashRecoveryContext.
   /// In that case, the control flow will resume after RunSafely(), like for a
   /// crash, rather than exiting the current process.
+  /// Use \arg NoCleanup for calling _exit() instead of exit().
   LLVM_ATTRIBUTE_NORETURN
-  static void Exit(int RetCode);
+  static void Exit(int RetCode, bool NoCleanup = false);
 };
 
 }

diff  --git a/llvm/lib/Support/CrashRecoveryContext.cpp b/llvm/lib/Support/CrashRecoveryContext.cpp
index 7609f04cf68c..77f00189274f 100644
--- a/llvm/lib/Support/CrashRecoveryContext.cpp
+++ b/llvm/lib/Support/CrashRecoveryContext.cpp
@@ -442,6 +442,26 @@ void CrashRecoveryContext::HandleExit(int RetCode) {
   llvm_unreachable("Most likely setjmp wasn't called!");
 }
 
+bool CrashRecoveryContext::throwIfCrash(int RetCode) {
+#if defined(_WIN32)
+  // On Windows, the high bits are reserved for kernel return codes. Values
+  // starting with 0x80000000 are reserved for "warnings"; values of 0xC0000000
+  // and up are for "errors". In practice, both are interpreted as a
+  // non-continuable signal.
+  unsigned Code = ((unsigned)RetCode & 0xF0000000) >> 28;
+  if (Code != 0xC && Code != 8)
+    return false;
+  ::RaiseException(RetCode, 0, 0, NULL);
+#else
+  // On Unix, signals are represented by return codes of 128 or higher.
+  if (RetCode <= 128)
+    return false;
+  llvm::sys::unregisterHandlers();
+  raise(RetCode - 128);
+#endif
+  return true;
+}
+
 // FIXME: Portability.
 static void setThreadBackgroundPriority() {
 #ifdef __APPLE__

diff  --git a/llvm/lib/Support/Process.cpp b/llvm/lib/Support/Process.cpp
index 9f0b689ce6c8..8626117f2a0b 100644
--- a/llvm/lib/Support/Process.cpp
+++ b/llvm/lib/Support/Process.cpp
@@ -20,6 +20,8 @@
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Program.h"
 
+#include <stddef.h> // for _Exit
+
 using namespace llvm;
 using namespace sys;
 
@@ -91,10 +93,14 @@ static bool coreFilesPrevented = !LLVM_ENABLE_CRASH_DUMPS;
 bool Process::AreCoreFilesPrevented() { return coreFilesPrevented; }
 
 LLVM_ATTRIBUTE_NORETURN
-void Process::Exit(int RetCode) {
+void Process::Exit(int RetCode, bool NoCleanup) {
   if (CrashRecoveryContext *CRC = CrashRecoveryContext::GetCurrent())
     CRC->HandleExit(RetCode);
-  ::exit(RetCode);
+
+  if (NoCleanup)
+    _Exit(RetCode);
+  else
+    ::exit(RetCode);
 }
 
 // Include the platform-specific parts of this class.


        


More information about the llvm-commits mailing list