Perform runtime patching of signal handlers. (#3016)
This commit is contained in:
@@ -76,7 +76,7 @@ model {
|
||||
clangstubs(NativeLibrarySpec) {
|
||||
sources {
|
||||
c.source.srcDir 'prebuilt/nativeInteropStubs/c'
|
||||
cpp.source.srcDir 'prebuilt/nativeInteropStubs/cpp'
|
||||
cpp.source.srcDir 'src/nativeInteropStubs/cpp'
|
||||
}
|
||||
|
||||
binaries.all {
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#include <dlfcn.h>
|
||||
#if defined(__linux__)
|
||||
#include <link.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
extern "C" void clang_toggleCrashRecovery(unsigned isEnabled);
|
||||
|
||||
constexpr int signalsToCover[] = {
|
||||
SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGUSR1, SIGUSR2
|
||||
};
|
||||
|
||||
struct {
|
||||
void* handler;
|
||||
bool isSigaction;
|
||||
} oldSignalHandlers[sizeof(signalsToCover)/sizeof(signalsToCover[0])] = { 0 };
|
||||
|
||||
static int mySigaction(int sig, const struct sigaction *act, struct sigaction * oact) {
|
||||
for (int i = 0; i < sizeof(signalsToCover)/sizeof(signalsToCover[0]); i++) {
|
||||
if (sig == signalsToCover[i]) return 0;
|
||||
}
|
||||
return sigaction(sig, act, oact);
|
||||
}
|
||||
|
||||
static void checkSignalChaining() {
|
||||
struct sigaction oact;
|
||||
clang_toggleCrashRecovery(1);
|
||||
for (int i = 0; i < sizeof(signalsToCover)/sizeof(signalsToCover[0]); i++) {
|
||||
int sig = signalsToCover[i];
|
||||
if (sigaction(sig, nullptr, &oact) != 0) continue;
|
||||
if ((oact.sa_flags & SA_SIGINFO) == 0) {
|
||||
if (oldSignalHandlers[i].isSigaction) {
|
||||
fprintf(stderr, "ERROR: improperly changed signal flag for %d\n", sig);
|
||||
continue;
|
||||
}
|
||||
if (oldSignalHandlers[i].handler != (void*)oact.sa_handler) {
|
||||
fprintf(stderr, "ERROR: improperly changed signal handler for %d\n", sig);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (!oldSignalHandlers[i].isSigaction) {
|
||||
fprintf(stderr, "ERROR: improperly changed signal flag for %d\n", sig);
|
||||
continue;
|
||||
}
|
||||
void* action = (void*)oact.sa_sigaction;
|
||||
if (oldSignalHandlers[i].handler != action) {
|
||||
Dl_info info;
|
||||
const char* soname = "<unknown>";
|
||||
if (dladdr(action, &info) != 0) {
|
||||
soname = info.dli_fname;
|
||||
}
|
||||
fprintf(stderr, "ERROR: changed signal handler for %d from %p to %p: coming from %s\n",
|
||||
sig, oldSignalHandlers[i].handler, action, soname);
|
||||
}
|
||||
}
|
||||
}
|
||||
clang_toggleCrashRecovery(0);
|
||||
}
|
||||
|
||||
__attribute__((constructor))
|
||||
static void initSignalChaining() {
|
||||
void** base = 0;
|
||||
Dl_info info;
|
||||
|
||||
for (int i = 0; i < sizeof(signalsToCover)/sizeof(signalsToCover[0]); i++) {
|
||||
struct sigaction oact;
|
||||
int sig = signalsToCover[i];
|
||||
if (sigaction(signalsToCover[i], nullptr, &oact) == 0) {
|
||||
if ((oact.sa_flags & SA_SIGINFO) == 0) {
|
||||
oldSignalHandlers[i] = {(void*)oact.sa_handler, false};
|
||||
} else {
|
||||
oldSignalHandlers[i] = {(void*)oact.sa_sigaction, true};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (dladdr((void*)&clang_toggleCrashRecovery, &info) == 0) return;
|
||||
base = (void**)info.dli_fbase;
|
||||
|
||||
// Force resolving of lazy symbols.
|
||||
clang_toggleCrashRecovery(1);
|
||||
clang_toggleCrashRecovery(0);
|
||||
|
||||
// And then patch GOT.
|
||||
#if defined(__linux__)
|
||||
{
|
||||
// On Linux we have to be a bit tricky, as there's unmapped gap between code and GOT.
|
||||
struct link_map* linkmap = 0;
|
||||
if (dladdr1((void*)&clang_toggleCrashRecovery, &info, (void**)&linkmap, RTLD_DL_LINKMAP) == 0) return;
|
||||
base = (void**)linkmap->l_ld;
|
||||
}
|
||||
#endif
|
||||
for (int index = 0, patched = 0; patched < 1; index++) {
|
||||
void* value = base[index];
|
||||
if (value == &sigaction) {
|
||||
base[index] = (void*)mySigaction;
|
||||
patched++;
|
||||
}
|
||||
if (value == mySigaction) {
|
||||
patched++;
|
||||
}
|
||||
}
|
||||
|
||||
checkSignalChaining();
|
||||
}
|
||||
|
||||
#endif // defined(__linux__) || defined(__APPLE__)
|
||||
+1
-14
@@ -73,20 +73,7 @@ internal abstract class KonanCliRunner(
|
||||
"java.library.path" to "${project.konanHome}/konan/nativelib"
|
||||
)
|
||||
|
||||
override val environment = mutableMapOf("LIBCLANG_DISABLE_CRASH_RECOVERY" to "1").apply {
|
||||
// See https://docs.oracle.com/javase/10/vm/signal-chaining.htm
|
||||
val jre = System.getProperty("java.home")
|
||||
when (HostManager.host.family) {
|
||||
Family.OSX -> {
|
||||
put("DYLD_FORCE_FLAT_NAMESPACE", "0")
|
||||
put("DYLD_INSERT_LIBRARIES", "$jre/lib/libjsig.dylib")
|
||||
}
|
||||
Family.LINUX -> {
|
||||
put("LD_PRELOAD", "$jre/lib/amd64/libjsig.so")
|
||||
}
|
||||
else -> { /* No signal chaining required. */ }
|
||||
}
|
||||
}
|
||||
override val environment = mutableMapOf("LIBCLANG_DISABLE_CRASH_RECOVERY" to "1")
|
||||
|
||||
private fun String.escapeQuotes() = replace("\"", "\\\"")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user