diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp @@ -2459,9 +2459,11 @@ #endif internal_memcpy(&newact, act, sizeof(newact)); internal_sigfillset(&newact.sa_mask); - newact.sa_flags |= SA_SIGINFO; - if ((uptr)act->handler != sig_ign && (uptr)act->handler != sig_dfl) + if ((act->sa_flags & SA_SIGINFO) || + ((uptr)act->handler != sig_ign && (uptr)act->handler != sig_dfl)) { + newact.sa_flags |= SA_SIGINFO; newact.sigaction = sighandler; + } ReleaseStore(thr, pc, (uptr)&sigactions[sig]); act = &newact; } diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/replace_sigaction.cpp b/compiler-rt/test/sanitizer_common/TestCases/Posix/replace_sigaction.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/replace_sigaction.cpp @@ -0,0 +1,66 @@ +// RUN: %clangxx -std=c++11 -O0 -g %s -o %t && %run %t + +#include +#include +#include + +static bool sahandler_done; +static bool sasigaction_done; + +static void sahandler(int) { sahandler_done = true; } + +static void sasigaction(int, siginfo_t *, void *) { sasigaction_done = true; } + +template void install(T *handler, struct sigaction *prev) { + bool siginfo = handler == (T *)&sasigaction; + struct sigaction act = {}; + if (siginfo) { + act.sa_flags = SA_SIGINFO; + act.sa_sigaction = (decltype(act.sa_sigaction))handler; + } else { + act.sa_handler = (decltype(act.sa_handler))handler; + } + int ret = sigaction(SIGHUP, &act, prev); + assert(ret == 0); + + if (handler == (T *)&sahandler) { + sahandler_done = false; + raise(SIGHUP); + assert(sahandler_done); + } + + if (handler == (T *)&sasigaction) { + sasigaction_done = false; + raise(SIGHUP); + assert(sasigaction_done); + } +} + +template void test(T1 *from, T2 *to) { + install(from, nullptr); + struct sigaction prev = {}; + install(to, &prev); + + bool siginfo_from = (from == (T1 *)&sasigaction); + if (siginfo_from) { + assert(prev.sa_flags & SA_SIGINFO); + assert(prev.sa_sigaction == (decltype(prev.sa_sigaction))from); + } else { + assert((prev.sa_flags & SA_SIGINFO) == 0); + assert(prev.sa_handler == (decltype(prev.sa_handler))from); + } +} + +template void testAll(T *to) { + test(&sahandler, to); + test(&sasigaction, to); + test(SIG_IGN, to); + test(SIG_DFL, to); +} + +int main(void) { + testAll(&sahandler); + testAll(&sasigaction); + testAll(SIG_IGN); + testAll(SIG_DFL); +}