[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();