The POSIX standard [POSIX.1-2024](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap01.html#tag_18) specifies how the utility reacts to signals as follows. This includes clang when invoke through a invocation such as [c17](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/c17.html) ``` ASYNCHRONOUS EVENTS The ASYNCHRONOUS EVENTS section lists how the utility reacts to such events as signals and what signals are caught. Default Behavior: When this section is listed as "Default.", or it refers to "the standard action" for any signal, it means that the action taken as a result of the signal shall be as follows: If the action inherited from the invoking process, according to the rules of inheritance of signal actions defined in the System Interfaces volume of POSIX.1-2024, is for the signal to be ignored, the utility shall ignore the signal. If the action inherited from the invoking process, according to the rules of inheritance of signal actions defined in System Interfaces volume of POSIX.1-2024, is the default signal action, the result of the utility's execution shall be as if the default signal action had been taken. When the required action is for the signal to terminate the utility, the utility may catch the signal, perform some additional processing (such as deleting temporary files), restore the default signal action, and resignal itself. ``` This PR updates the LLVM/Clang’s behavior accordingly by not installing a signal handler when the inherited disposition is `SIG_IGN`, and by ensuring that the exit code reflects the terminating signal number, resignaling after the signal is handled. Additionally, test cases have been updated to expect failures due to signals/crashes rather than regular errors. [<signal.h>](https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/signal.h.html) specifies the default action of signals.
148 lines
4.7 KiB
C++
148 lines
4.7 KiB
C++
//===-- InitLLVM.cpp -----------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Support/InitLLVM.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/AutoConvert.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/ManagedStatic.h"
|
|
#include "llvm/Support/Signals.h"
|
|
|
|
#ifdef _WIN32
|
|
#include "llvm/Support/Windows/WindowsSupport.h"
|
|
#endif
|
|
|
|
#if defined(HAVE_UNISTD_H)
|
|
#include <unistd.h>
|
|
#else
|
|
#ifndef STDIN_FILENO
|
|
#define STDIN_FILENO 0
|
|
#endif
|
|
#ifndef STDOUT_FILENO
|
|
#define STDOUT_FILENO 1
|
|
#endif
|
|
#ifndef STDERR_FILENO
|
|
#define STDERR_FILENO 2
|
|
#endif
|
|
#endif
|
|
|
|
static void RaiseLimits() {
|
|
#ifdef _AIX
|
|
// AIX has restrictive memory soft-limits out-of-box, so raise them if needed.
|
|
auto RaiseLimit = [](int resource) {
|
|
struct rlimit r;
|
|
getrlimit(resource, &r);
|
|
|
|
// Increase the soft limit to the hard limit, if necessary and
|
|
// possible.
|
|
if (r.rlim_cur != RLIM_INFINITY && r.rlim_cur != r.rlim_max) {
|
|
r.rlim_cur = r.rlim_max;
|
|
setrlimit(resource, &r);
|
|
}
|
|
};
|
|
|
|
// Address space size.
|
|
RaiseLimit(RLIMIT_AS);
|
|
// Heap size.
|
|
RaiseLimit(RLIMIT_DATA);
|
|
// Stack size.
|
|
RaiseLimit(RLIMIT_STACK);
|
|
#ifdef RLIMIT_RSS
|
|
// Resident set size.
|
|
RaiseLimit(RLIMIT_RSS);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void CleanupStdHandles(void *Cookie) {
|
|
llvm::raw_ostream *Outs = &llvm::outs(), *Errs = &llvm::errs();
|
|
Outs->flush();
|
|
Errs->flush();
|
|
llvm::restoreStdHandleAutoConversion(STDIN_FILENO);
|
|
llvm::restoreStdHandleAutoConversion(STDOUT_FILENO);
|
|
llvm::restoreStdHandleAutoConversion(STDERR_FILENO);
|
|
}
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::sys;
|
|
|
|
InitLLVM::InitLLVM(int &Argc, const char **&Argv,
|
|
bool InstallPipeSignalExitHandler,
|
|
bool NeedsPOSIXUtilitySignalHandling) {
|
|
#ifndef NDEBUG
|
|
static std::atomic<bool> Initialized{false};
|
|
assert(!Initialized && "InitLLVM was already initialized!");
|
|
Initialized = true;
|
|
#endif
|
|
|
|
// Bring stdin/stdout/stderr into a known state.
|
|
#ifdef _WIN32
|
|
sys::AddSignalHandler(CleanupStdHandles, nullptr);
|
|
#else
|
|
sys::AddSignalHandler(CleanupStdHandles, nullptr,
|
|
NeedsPOSIXUtilitySignalHandling);
|
|
#endif
|
|
|
|
if (InstallPipeSignalExitHandler)
|
|
// The pipe signal handler must be installed before any other handlers are
|
|
// registered. This is because the Unix \ref RegisterHandlers function does
|
|
// not perform a sigaction() for SIGPIPE unless a one-shot handler is
|
|
// present, to allow long-lived processes (like lldb) to fully opt-out of
|
|
// llvm's SIGPIPE handling and ignore the signal safely.
|
|
sys::SetOneShotPipeSignalFunction(sys::DefaultOneShotPipeSignalHandler);
|
|
// Initialize the stack printer after installing the one-shot pipe signal
|
|
// handler, so we can perform a sigaction() for SIGPIPE on Unix if requested.
|
|
StackPrinter.emplace(Argc, Argv);
|
|
sys::PrintStackTraceOnErrorSignal(Argv[0]);
|
|
install_out_of_memory_new_handler();
|
|
RaiseLimits();
|
|
|
|
#ifdef __MVS__
|
|
|
|
// We use UTF-8 as the internal character encoding. On z/OS, all external
|
|
// output is encoded in EBCDIC. In order to be able to read all
|
|
// error messages, we turn conversion to EBCDIC on for stderr fd.
|
|
std::string Banner = std::string(Argv[0]) + ": ";
|
|
ExitOnError ExitOnErr(Banner);
|
|
|
|
// If turning on conversion for stderr fails then the error message
|
|
// may be garbled. There is no solution to this problem.
|
|
ExitOnErr(errorCodeToError(llvm::enableAutoConversion(STDERR_FILENO)));
|
|
ExitOnErr(errorCodeToError(llvm::enableAutoConversion(STDOUT_FILENO)));
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
// We use UTF-8 as the internal character encoding. On Windows,
|
|
// arguments passed to main() may not be encoded in UTF-8. In order
|
|
// to reliably detect encoding of command line arguments, we use an
|
|
// Windows API to obtain arguments, convert them to UTF-8, and then
|
|
// write them back to the Argv vector.
|
|
//
|
|
// There's probably other way to do the same thing (e.g. using
|
|
// wmain() instead of main()), but this way seems less intrusive
|
|
// than that.
|
|
std::string Banner = std::string(Argv[0]) + ": ";
|
|
ExitOnError ExitOnErr(Banner);
|
|
|
|
ExitOnErr(errorCodeToError(windows::GetCommandLineArguments(Args, Alloc)));
|
|
|
|
// GetCommandLineArguments doesn't terminate the vector with a
|
|
// nullptr. Do it to make it compatible with the real argv.
|
|
Args.push_back(nullptr);
|
|
|
|
Argc = Args.size() - 1;
|
|
Argv = Args.data();
|
|
#endif
|
|
}
|
|
|
|
InitLLVM::~InitLLVM() {
|
|
CleanupStdHandles(nullptr);
|
|
llvm_shutdown();
|
|
}
|