Skip to content

Commit b3d9e4b

Browse files
committed
Don't install signal handler if the disposition of a signal is SIG_IGN, resignal after the signal handler handles a signal so the exit code of the compiler contains the signal number.
1 parent d5927a6 commit b3d9e4b

File tree

5 files changed

+58
-12
lines changed

5 files changed

+58
-12
lines changed

clang-tools-extra/clangd/unittests/ThreadCrashReporterTests.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@
1313
#include <csignal>
1414
#include <string>
1515

16+
// According to the POSIX specification, if the inherited disposition of a
17+
// signal is the default action, the behavior of utilitys must be as if the
18+
// default action had been taken. When the required default action is to
19+
// terminate the process, such as for SIGUSR1, the utility may catch the
20+
// signal, perform additional processing, restore the default disposition,
21+
// and then re-signal itself. This causes the process to terminate as
22+
// required. Because of this behavior, the crash-reporter test here is not
23+
// suitable for Unix platforms.
24+
25+
#ifndef LLVM_ON_UNIX
26+
1627
namespace clang {
1728
namespace clangd {
1829

@@ -76,3 +87,4 @@ TEST(ThreadCrashReporterTest, All) {
7687
} // namespace
7788
} // namespace clangd
7889
} // namespace clang
90+
#endif // !LLVM_ON_UNIX

clang/lib/Driver/Driver.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2298,7 +2298,14 @@ int Driver::ExecuteCompilation(
22982298

22992299
if (!FailingCommand->getCreator().hasGoodDiagnostics() || CommandRes != 1) {
23002300
// FIXME: See FIXME above regarding result code interpretation.
2301+
#if LLVM_ON_UNIX
2302+
// On Unix, signals are represented by return codes of 128 plus the
2303+
// signal number. Return code 255 is excluded because some tools,
2304+
// such as llvm-ifs, exit with code 255 (-1) on failure.
2305+
if (CommandRes > 128 && CommandRes != 255)
2306+
#else
23012307
if (CommandRes < 0)
2308+
#endif
23022309
Diag(clang::diag::err_drv_command_signalled)
23032310
<< FailingTool.getShortName();
23042311
else

clang/tools/driver/driver.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
#include <optional>
5555
#include <set>
5656
#include <system_error>
57+
#if LLVM_ON_UNIX
58+
#include <signal.h>
59+
#endif
5760

5861
using namespace clang;
5962
using namespace clang::driver;
@@ -400,14 +403,15 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
400403
Driver::CommandStatus CommandStatus = Driver::CommandStatus::Ok;
401404
// Pretend the first command failed if ReproStatus is Always.
402405
const Command *FailingCommand = nullptr;
406+
int CommandRes = 0;
403407
if (!C->getJobs().empty())
404408
FailingCommand = &*C->getJobs().begin();
405409
if (C && !C->containsError()) {
406410
SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
407411
Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
408412

409413
for (const auto &P : FailingCommands) {
410-
int CommandRes = P.first;
414+
CommandRes = P.first;
411415
FailingCommand = P.second;
412416
if (!Res)
413417
Res = CommandRes;
@@ -464,6 +468,18 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
464468
Res = 1;
465469
#endif
466470

471+
#if LLVM_ON_UNIX
472+
// On Unix, signals are represented by return codes of 128 plus the signal
473+
// number. If the return code indicates it was from a signal handler, raise
474+
// the signal so that the exit code includes the signal number, as required
475+
// by POSIX. Return code 255 is excluded because some tools, such as
476+
// llvm-ifs, exit with code 255 (-1) on failure.
477+
if (CommandRes > 128 && CommandRes != 255) {
478+
llvm::sys::unregisterHandlers();
479+
raise(CommandRes - 128);
480+
}
481+
#endif
482+
467483
// If we have multiple failing commands, we return the result of the first
468484
// failing command.
469485
return Res;

llvm/lib/Support/CrashRecoveryContext.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,11 @@ static void installExceptionOrSignalHandlers() {
398398
sigemptyset(&Handler.sa_mask);
399399

400400
for (unsigned i = 0; i != NumSignals; ++i) {
401-
sigaction(Signals[i], &Handler, &PrevActions[i]);
401+
struct sigaction act;
402+
sigaction(Signals[i], NULL, &act);
403+
// Don't install signal handler if the disposition of a signal is SIG_IGN.
404+
if (act.sa_handler != SIG_IGN)
405+
sigaction(Signals[i], &Handler, &PrevActions[i]);
402406
}
403407
}
404408

llvm/lib/Support/Unix/Signals.inc

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -327,8 +327,12 @@ static void RegisterHandlers() { // Not signal-safe.
327327
}
328328
sigemptyset(&NewHandler.sa_mask);
329329

330-
// Install the new handler, save the old one in RegisteredSignalInfo.
331-
sigaction(Signal, &NewHandler, &RegisteredSignalInfo[Index].SA);
330+
// Install the new handler if the signal disposition isn't SIG_IGN,
331+
// save the old one in RegisteredSignalInfo.
332+
struct sigaction act;
333+
sigaction(Signal, NULL, &act);
334+
if (act.sa_handler != SIG_IGN)
335+
sigaction(Signal, &NewHandler, &RegisteredSignalInfo[Index].SA);
332336
RegisteredSignalInfo[Index].SigNo = Signal;
333337
++NumRegisteredSignals;
334338
};
@@ -408,14 +412,12 @@ static void SignalHandler(int Sig, siginfo_t *Info, void *) {
408412
// Otherwise if it is a fault (like SEGV) run any handler.
409413
llvm::sys::RunSignalHandlers();
410414

411-
#ifdef __s390__
412-
// On S/390, certain signals are delivered with PSW Address pointing to
413-
// *after* the faulting instruction. Simply returning from the signal
414-
// handler would continue execution after that point, instead of
415-
// re-raising the signal. Raise the signal manually in those cases.
416-
if (Sig == SIGILL || Sig == SIGFPE || Sig == SIGTRAP)
417-
raise(Sig);
418-
#endif
415+
// Resignal if it is a kill signal so that the exit code contains the
416+
// terminating signal number.
417+
if (llvm::is_contained(KillSigs, Sig)) {
418+
raise(Sig); // Execute the default handler.
419+
return;
420+
}
419421

420422
#if defined(__linux__)
421423
// Re-raising a signal via `raise` loses the original siginfo. Recent
@@ -438,6 +440,11 @@ static void InfoSignalHandler(int Sig) {
438440
SaveAndRestore SaveErrnoDuringASignalHandler(errno);
439441
if (SignalHandlerFunctionType CurrentInfoFunction = InfoSignalFunction)
440442
CurrentInfoFunction();
443+
444+
if (Sig == SIGUSR1) {
445+
sys::unregisterHandlers();
446+
raise(Sig);
447+
}
441448
}
442449

443450
void llvm::sys::RunInterruptHandlers() { RemoveFilesToRemove(); }

0 commit comments

Comments
 (0)