summaryrefslogtreecommitdiff
path: root/lld/tools
diff options
context:
space:
mode:
authorAlexandre Ganea <alexandre.ganea@ubisoft.com>2020-11-12 08:14:20 -0500
committerAlexandre Ganea <alexandre.ganea@ubisoft.com>2020-11-12 08:14:43 -0500
commit45b8a741fbbf271e0fb71294cb7cdce3ad4b9bf3 (patch)
tree36f232547cfcc617e32d65736908a71758094d14 /lld/tools
parentf37834c7dcbe69405bf3e182d2b3e3227cc4a569 (diff)
downloadllvm-45b8a741fbbf271e0fb71294cb7cdce3ad4b9bf3.tar.gz
[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
Diffstat (limited to 'lld/tools')
-rw-r--r--lld/tools/lld/lld.cpp13
1 files changed, 2 insertions, 11 deletions
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;
}