Index: compiler-rt/trunk/lib/asan/asan_interceptors.cc =================================================================== --- compiler-rt/trunk/lib/asan/asan_interceptors.cc +++ compiler-rt/trunk/lib/asan/asan_interceptors.cc @@ -357,28 +357,22 @@ #if SANITIZER_ANDROID INTERCEPTOR(void*, bsd_signal, int signum, void *handler) { - if (!IsHandledDeadlySignal(signum) || - common_flags()->allow_user_segv_handler) { + if (GetHandleSignalMode(signum) != kHandleSignalExclusive) return REAL(bsd_signal)(signum, handler); - } return 0; } #endif INTERCEPTOR(void*, signal, int signum, void *handler) { - if (!IsHandledDeadlySignal(signum) || - common_flags()->allow_user_segv_handler) { + if (GetHandleSignalMode(signum) != kHandleSignalExclusive) return REAL(signal)(signum, handler); - } return nullptr; } INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act, struct sigaction *oldact) { - if (!IsHandledDeadlySignal(signum) || - common_flags()->allow_user_segv_handler) { + if (GetHandleSignalMode(signum) != kHandleSignalExclusive) return REAL(sigaction)(signum, act, oldact); - } return 0; } Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h @@ -380,7 +380,7 @@ // Functions related to signal handling. typedef void (*SignalHandlerType)(int, void *, void *); -bool IsHandledDeadlySignal(int signum); +HandleSignalMode GetHandleSignalMode(int signum); void InstallDeadlySignalHandlers(SignalHandlerType handler); const char *DescribeSignalOrException(int signo); // Alternative signal stack (POSIX-only). Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flag_parser.h =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flag_parser.h +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flag_parser.h @@ -64,6 +64,11 @@ *t_ = b ? kHandleSignalYes : kHandleSignalNo; return true; } + if (internal_strcmp(value, "2") == 0 || + internal_strcmp(value, "exclusive") == 0) { + *t_ = kHandleSignalExclusive; + return true; + } Printf("ERROR: Invalid value for signal handler option: '%s'\n", value); return false; } Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h @@ -21,6 +21,7 @@ enum HandleSignalMode { kHandleSignalNo, kHandleSignalYes, + kHandleSignalExclusive, }; struct CommonFlags { Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc @@ -80,7 +80,8 @@ COMMON_FLAG(bool, check_printf, true, "Check printf arguments.") #define COMMON_FLAG_HANDLE_SIGNAL_HELP(signal) \ "Controls custom tool's " #signal " handler (0 - do not registers the " \ - "handler, 1 - register the handler). " + "handler, 1 - register the handler and allow user to set own, " \ + "2 - registers the handler and block user from changing it). " COMMON_FLAG(HandleSignalMode, handle_segv, kHandleSignalYes, COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGSEGV)) COMMON_FLAG(HandleSignalMode, handle_sigbus, kHandleSignalYes, @@ -92,9 +93,6 @@ COMMON_FLAG(HandleSignalMode, handle_sigfpe, kHandleSignalYes, COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGFPE)) #undef COMMON_FLAG_HANDLE_SIGNAL_HELP -COMMON_FLAG(bool, allow_user_segv_handler, true, - "If set, allows user to register a SEGV handler even if the tool " - "registers one.") COMMON_FLAG(bool, use_sigaltstack, true, "If set, uses alternate stack for signal handling.") COMMON_FLAG(bool, detect_deadlocks, false, Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc @@ -1394,7 +1394,7 @@ #endif -bool IsHandledDeadlySignal(int signum) { +HandleSignalMode GetHandleSignalMode(int signum) { switch (signum) { case SIGABRT: return common_flags()->handle_abort; @@ -1407,7 +1407,7 @@ case SIGBUS: return common_flags()->handle_sigbus; } - return false; + return kHandleSignalNo; } #if !SANITIZER_GO Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc @@ -414,10 +414,10 @@ memory_mapping.DumpListOfModules(&modules_); } -bool IsHandledDeadlySignal(int signum) { +HandleSignalMode GetHandleSignalMode(int signum) { // Handling fatal signals on watchOS and tvOS devices is disallowed. if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM)) - return false; + return kHandleSignalNo; switch (signum) { case SIGABRT: return common_flags()->handle_abort; @@ -430,7 +430,7 @@ case SIGBUS: return common_flags()->handle_sigbus; } - return false; + return kHandleSignalNo; } MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED; Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix_libcdep.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -134,7 +134,8 @@ void Abort() { #if !SANITIZER_GO // If we are handling SIGABRT, unhandle it first. - if (IsHandledDeadlySignal(SIGABRT)) { + // TODO(vitalybuka): Check if handler belongs to sanitizer. + if (GetHandleSignalMode(SIGABRT) != kHandleSignalNo) { struct sigaction sigact; internal_memset(&sigact, 0, sizeof(sigact)); sigact.sa_sigaction = (sa_sigaction_t)SIG_DFL; @@ -188,8 +189,8 @@ static void MaybeInstallSigaction(int signum, SignalHandlerType handler) { - if (!IsHandledDeadlySignal(signum)) - return; + if (GetHandleSignalMode(signum) == kHandleSignalNo) return; + struct sigaction sigact; internal_memset(&sigact, 0, sizeof(sigact)); sigact.sa_sigaction = (sa_sigaction_t)handler; Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc @@ -832,9 +832,9 @@ // FIXME: Decide what to do on Windows. } -bool IsHandledDeadlySignal(int signum) { +HandleSignalMode GetHandleSignalMode(int signum) { // FIXME: Decide what to do on Windows. - return false; + return kHandleSignalNo; } // Check based on flags if we should handle this exception. Index: compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_flags_test.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_flags_test.cc +++ compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_flags_test.cc @@ -78,13 +78,15 @@ TestFlag(kHandleSignalYes, "flag_name=0", kHandleSignalNo); TestFlag(kHandleSignalYes, "flag_name=no", kHandleSignalNo); TestFlag(kHandleSignalYes, "flag_name=false", kHandleSignalNo); + TestFlag(kHandleSignalNo, "flag_name=2", kHandleSignalExclusive); + TestFlag(kHandleSignalYes, "flag_name=exclusive", kHandleSignalExclusive); EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name", kHandleSignalNo), "expected '='"); EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name=", kHandleSignalNo), "Invalid value for signal handler option: ''"); - EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name=2", kHandleSignalNo), - "Invalid value for signal handler option: '2'"); + EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name=3", kHandleSignalNo), + "Invalid value for signal handler option: '3'"); EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name=-1", kHandleSignalNo), "Invalid value for signal handler option: '-1'"); EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name=on", kHandleSignalNo), Index: compiler-rt/trunk/test/asan/TestCases/Posix/allow_user_segv.cc =================================================================== --- compiler-rt/trunk/test/asan/TestCases/Posix/allow_user_segv.cc +++ compiler-rt/trunk/test/asan/TestCases/Posix/allow_user_segv.cc @@ -1,8 +1,14 @@ // Regression test for // https://code.google.com/p/address-sanitizer/issues/detail?id=180 -// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=allow_user_segv_handler=true not %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -O2 %s -o %t && %env_asan_opts=allow_user_segv_handler=true not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 +// RUN: %clangxx_asan -O2 %s -o %t && %env_asan_opts=handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 + +// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 +// RUN: %clangxx_asan -O2 %s -o %t && %env_asan_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 + +// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 +// RUN: %clangxx_asan -O2 %s -o %t && %env_asan_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 #include #include @@ -22,10 +28,14 @@ printf("Invalid signum"); exit(1); } - if (original_sigaction.sa_flags | SA_SIGINFO) - original_sigaction.sa_sigaction(signum, siginfo, context); - else - original_sigaction.sa_handler(signum); + if (original_sigaction.sa_flags | SA_SIGINFO) { + if (original_sigaction.sa_sigaction) + original_sigaction.sa_sigaction(signum, siginfo, context); + } else { + if (original_sigaction.sa_handler) + original_sigaction.sa_handler(signum); + } + exit(1); } int DoSEGV() { @@ -33,27 +43,38 @@ return *x; } -int InstallHandler(int signum, struct sigaction *original_sigaction) { +bool InstallHandler(int signum, struct sigaction *original_sigaction) { struct sigaction user_sigaction; user_sigaction.sa_sigaction = User_OnSIGSEGV; user_sigaction.sa_flags = SA_SIGINFO; if (sigaction(signum, &user_sigaction, original_sigaction)) { perror("sigaction"); - return 1; + return false; } - return 0; + return true; } int main() { // Let's install handlers for both SIGSEGV and SIGBUS, since pre-Yosemite // 32-bit Darwin triggers SIGBUS instead. - if (InstallHandler(SIGSEGV, &original_sigaction_sigsegv)) return 1; - if (InstallHandler(SIGBUS, &original_sigaction_sigbus)) return 1; - fprintf(stderr, "User sigaction installed\n"); + if (InstallHandler(SIGSEGV, &original_sigaction_sigsegv) && + InstallHandler(SIGBUS, &original_sigaction_sigbus)) { + fprintf(stderr, "User sigaction installed\n"); + } return DoSEGV(); } -// CHECK: User sigaction installed -// CHECK-NEXT: User sigaction called -// CHECK-NEXT: ASAN:DEADLYSIGNAL -// CHECK: AddressSanitizer: SEGV on unknown address +// CHECK0-NOT: ASAN:DEADLYSIGNAL +// CHECK0-NOT: AddressSanitizer: SEGV on unknown address +// CHECK0: User sigaction installed +// CHECK0-NEXT: User sigaction called + +// CHECK1: User sigaction installed +// CHECK1-NEXT: User sigaction called +// CHECK1-NEXT: ASAN:DEADLYSIGNAL +// CHECK1: AddressSanitizer: SEGV on unknown address + +// CHECK2-NOT: User sigaction called +// CHECK2: User sigaction installed +// CHECK2-NEXT: ASAN:DEADLYSIGNAL +// CHECK2: AddressSanitizer: SEGV on unknown address Index: compiler-rt/trunk/test/sanitizer_common/TestCases/Linux/signal_segv_handler.cc =================================================================== --- compiler-rt/trunk/test/sanitizer_common/TestCases/Linux/signal_segv_handler.cc +++ compiler-rt/trunk/test/sanitizer_common/TestCases/Linux/signal_segv_handler.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx -O1 %s -o %t && TSAN_OPTIONS="flush_memory_ms=1 memory_limit_mb=1" ASAN_OPTIONS="handle_segv=0 allow_user_segv_handler=1" %run %t 2>&1 | FileCheck %s +// RUN: %clangxx -O1 %s -o %t && TSAN_OPTIONS="flush_memory_ms=1 memory_limit_mb=1" ASAN_OPTIONS="handle_segv=0" %run %t 2>&1 | FileCheck %s // JVM uses SEGV to preempt threads. All threads do a load from a known address // periodically. When runtime needs to preempt threads, it unmaps the page.