[compiler-rt] [TSan][Darwin] Add _longjmp interceptor for Apple platforms (PR #163384)

Dan Blackwell via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 26 04:27:07 PST 2025


https://github.com/DanBlackwell updated https://github.com/llvm/llvm-project/pull/163384

>From e0e752f9c640db63873126a32641a644f3998a31 Mon Sep 17 00:00:00 2001
From: Dan Blackwell <dan_blackwell at apple.com>
Date: Tue, 14 Oct 2025 13:35:59 +0100
Subject: [PATCH] [TSan][Darwin] Add _longjmp interceptor for Apple platforms

As noted in https://github.com/llvm/llvm-project/issues/161443, currently _longjmp is not intercepted. This results in the callstack being incorrect after a call to _longjmp, and in the worst case overflowing with many calls.

This patch adds the missing interceptor, and a test to make sure that the callstack is correctly maintained.
---
 .../lib/tsan/rtl/tsan_interceptors_posix.cpp  |  2 +-
 compiler-rt/test/tsan/setjmp_longjmp.c        | 55 +++++++++++++++++++
 2 files changed, 56 insertions(+), 1 deletion(-)
 create mode 100644 compiler-rt/test/tsan/setjmp_longjmp.c

diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
index 0c358042d1b56..97a1eed719c84 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
@@ -649,7 +649,7 @@ TSAN_INTERCEPTOR(void, siglongjmp_symname, uptr *env, int val) {
   REAL(siglongjmp_symname)(env, val);
 }
 
-#if SANITIZER_NETBSD
+#if SANITIZER_NETBSD || SANITIZER_APPLE
 TSAN_INTERCEPTOR(void, _longjmp, uptr *env, int val) {
   {
     SCOPED_INTERCEPTOR_RAW(_longjmp, env, val);
diff --git a/compiler-rt/test/tsan/setjmp_longjmp.c b/compiler-rt/test/tsan/setjmp_longjmp.c
new file mode 100644
index 0000000000000..ed4d4c9200ec5
--- /dev/null
+++ b/compiler-rt/test/tsan/setjmp_longjmp.c
@@ -0,0 +1,55 @@
+// RUN: %clang_tsan %s -o %t
+// RUN: %deflake %run %t | FileCheck %s
+//
+// XFAIL: {{.*linux.*}}
+
+#include <pthread.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int globalVar;
+
+void foo(jmp_buf *buf, char willExit) {
+  if (willExit)
+    globalVar = 1;
+  _longjmp(*buf, 1);
+}
+
+void func2() {
+  jmp_buf buf;
+  const int reps = 1000;
+  for (int i = 0; i < reps; i++) {
+    if (_setjmp(buf) == 0) {
+      foo(&buf, i == reps - 1);
+    }
+  }
+}
+
+void *writeGlobal(void *ctx) {
+  func2();
+  return NULL;
+}
+
+void *readGlobal(void *ctx) {
+  sleep(1);
+  printf("globalVar: %d\n", globalVar);
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, writeGlobal, NULL);
+  pthread_create(&t[1], NULL, readGlobal, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK:   Read of size 4 at {{.*}} by thread
+// CHECK:     #0 readGlobal
+// CHECK:   Previous write of size 4 at {{.*}} by thread
+// CHECK:     #0 foo
+// CHECK:     #1 func2
+// CHECK:     #2 writeGlobal



More information about the llvm-commits mailing list