[dfsan] Clean TLS after signal callbacks
Similar to https://reviews.llvm.org/D95642, this diff fixes signal.
Reviewed-by: morehouse
Differential Revision: https://reviews.llvm.org/D95896
GitOrigin-RevId: 93afc3452cd4ebdb145e309f4d82f82e2f496479
diff --git a/lib/dfsan/dfsan_custom.cpp b/lib/dfsan/dfsan_custom.cpp
index 5ecd569..f90c8e8 100644
--- a/lib/dfsan/dfsan_custom.cpp
+++ b/lib/dfsan/dfsan_custom.cpp
@@ -952,6 +952,29 @@
}
SANITIZER_INTERFACE_ATTRIBUTE
+sighandler_t __dfsw_signal(int signum,
+ void *(*handler_trampoline)(void *, int, dfsan_label,
+ dfsan_label *),
+ sighandler_t handler, dfsan_label signum_label,
+ dfsan_label handler_label, dfsan_label *ret_label) {
+ CHECK_LT(signum, kMaxSignals);
+ SignalSpinLocker lock;
+ uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed);
+ if (handler != SIG_IGN && handler != SIG_DFL) {
+ atomic_store(&sigactions[signum], (uptr)handler, memory_order_relaxed);
+ handler = &SignalHandler;
+ }
+
+ sighandler_t ret = signal(signum, handler);
+
+ if (ret == SignalHandler)
+ ret = (sighandler_t)old_cb;
+
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
int __dfsw_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
dfsan_label old_ss_label, dfsan_label *ret_label) {
int ret = sigaltstack(ss, old_ss);
diff --git a/lib/dfsan/done_abilist.txt b/lib/dfsan/done_abilist.txt
index 6db03b4..1ceabf1 100644
--- a/lib/dfsan/done_abilist.txt
+++ b/lib/dfsan/done_abilist.txt
@@ -253,6 +253,7 @@
fun:select=custom
fun:sigemptyset=custom
fun:sigaction=custom
+fun:signal=custom
fun:gettimeofday=custom
# sprintf-like
diff --git a/test/dfsan/custom.cpp b/test/dfsan/custom.cpp
index 48fc9d0..94ca7a8 100644
--- a/test/dfsan/custom.cpp
+++ b/test/dfsan/custom.cpp
@@ -853,6 +853,20 @@
assert(oldact.sa_handler == SignalHandler);
}
+void test_signal() {
+ // Set signal to be SignalHandler, save the previous one into
+ // old_signal_handler.
+ sighandler_t old_signal_handler = signal(SIGHUP, SignalHandler);
+ ASSERT_ZERO_LABEL(old_signal_handler);
+
+ // Set SIG_IGN or SIG_DFL, and check the previous one is expected.
+ assert(SignalHandler == signal(SIGHUP, SIG_DFL));
+ assert(SIG_DFL == signal(SIGHUP, SIG_IGN));
+
+ // Restore signal to old_signal_handler.
+ assert(SIG_IGN == signal(SIGHUP, old_signal_handler));
+}
+
void test_sigaltstack() {
stack_t old_altstack = {};
dfsan_set_label(j_label, &old_altstack, sizeof(old_altstack));
@@ -1323,6 +1337,7 @@
test_sched_getaffinity();
test_select();
test_sigaction();
+ test_signal();
test_sigaltstack();
test_sigemptyset();
test_snprintf();