From faafeea7195e55417979fb65f6728b8b4cf7c389 Mon Sep 17 00:00:00 2001 From: Nikolay Igotti Date: Mon, 27 May 2019 18:45:27 +0300 Subject: [PATCH] Perform runtime patching of signal handlers. (#3016) --- Interop/Indexer/build.gradle | 2 +- .../cpp/disable-abi-checks.cpp | 0 .../nativeInteropStubs/cpp/signalChaining.cpp | 110 ++++++++++++++++++ .../gradle/plugin/konan/KonanToolRunner.kt | 15 +-- 4 files changed, 112 insertions(+), 15 deletions(-) rename Interop/Indexer/{prebuilt => src}/nativeInteropStubs/cpp/disable-abi-checks.cpp (100%) create mode 100644 Interop/Indexer/src/nativeInteropStubs/cpp/signalChaining.cpp diff --git a/Interop/Indexer/build.gradle b/Interop/Indexer/build.gradle index d2d849897d7..48dd53b3603 100644 --- a/Interop/Indexer/build.gradle +++ b/Interop/Indexer/build.gradle @@ -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 { diff --git a/Interop/Indexer/prebuilt/nativeInteropStubs/cpp/disable-abi-checks.cpp b/Interop/Indexer/src/nativeInteropStubs/cpp/disable-abi-checks.cpp similarity index 100% rename from Interop/Indexer/prebuilt/nativeInteropStubs/cpp/disable-abi-checks.cpp rename to Interop/Indexer/src/nativeInteropStubs/cpp/disable-abi-checks.cpp diff --git a/Interop/Indexer/src/nativeInteropStubs/cpp/signalChaining.cpp b/Interop/Indexer/src/nativeInteropStubs/cpp/signalChaining.cpp new file mode 100644 index 00000000000..5e5a10ac0d5 --- /dev/null +++ b/Interop/Indexer/src/nativeInteropStubs/cpp/signalChaining.cpp @@ -0,0 +1,110 @@ +#if defined(__linux__) || defined(__APPLE__) +#include +#if defined(__linux__) +#include +#endif +#include +#include + +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 = ""; + 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__) diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/KonanToolRunner.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/KonanToolRunner.kt index e38d7a6099f..9b6db5fcc39 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/KonanToolRunner.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/KonanToolRunner.kt @@ -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("\"", "\\\"")