[libunwind] [clang] [libc] [compiler-rt] [libcxx] [clang-tools-extra] [flang] [lldb] [lld] [mlir] [libcxxabi] [llvm] [hwasan] Improve support of forking with threads (PR #75291)

Vitaly Buka via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 13 14:49:33 PST 2023


https://github.com/vitalybuka updated https://github.com/llvm/llvm-project/pull/75291

>From 1a361826b5345460c201c506f2d2c78a84aebf84 Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Tue, 12 Dec 2023 22:59:10 -0800
Subject: [PATCH 1/4] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20ch?=
 =?UTF-8?q?anges=20to=20main=20this=20commit=20is=20based=20on?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.4

[skip ci]
---
 .../include/sanitizer/hwasan_interface.h      |  4 ++++
 compiler-rt/lib/asan/asan_fuchsia.cpp         |  2 ++
 compiler-rt/lib/asan/asan_internal.h          |  1 +
 compiler-rt/lib/asan/asan_posix.cpp           | 24 +++++++++++++++++++
 compiler-rt/lib/asan/asan_rtl.cpp             |  2 ++
 compiler-rt/lib/asan/asan_win.cpp             |  2 ++
 compiler-rt/lib/hwasan/hwasan.cpp             |  2 ++
 compiler-rt/lib/hwasan/hwasan.h               |  6 ++---
 .../lib/hwasan/hwasan_interface_internal.h    |  3 +++
 compiler-rt/lib/lsan/lsan.cpp                 |  1 +
 compiler-rt/lib/lsan/lsan.h                   |  1 +
 compiler-rt/lib/lsan/lsan_common.cpp          |  3 +++
 compiler-rt/lib/lsan/lsan_common.h            |  4 ++++
 compiler-rt/lib/lsan/lsan_fuchsia.cpp         |  1 +
 compiler-rt/lib/lsan/lsan_posix.cpp           | 18 ++++++++++++++
 compiler-rt/test/hwasan/TestCases/tag-ptr.cpp | 24 +++++++++++++++++++
 .../TestCases/Posix/fork_threaded.c           |  2 +-
 .../sanitizer_common/sanitizer_specific.h     | 13 ++++++++++
 18 files changed, 109 insertions(+), 4 deletions(-)
 create mode 100644 compiler-rt/test/hwasan/TestCases/tag-ptr.cpp

diff --git a/compiler-rt/include/sanitizer/hwasan_interface.h b/compiler-rt/include/sanitizer/hwasan_interface.h
index abe310c0666948..407f488a24a617 100644
--- a/compiler-rt/include/sanitizer/hwasan_interface.h
+++ b/compiler-rt/include/sanitizer/hwasan_interface.h
@@ -44,6 +44,10 @@ void SANITIZER_CDECL __hwasan_tag_memory(const volatile void *p,
 void *SANITIZER_CDECL __hwasan_tag_pointer(const volatile void *p,
                                            unsigned char tag);
 
+/// Get tag from the pointer.
+unsigned char SANITIZER_CDECL
+__hwasan_get_tag_from_pointer(const volatile void *p);
+
 // Set memory tag from the current SP address to the given address to zero.
 // This is meant to annotate longjmp and other non-local jumps.
 // This function needs to know the (almost) exact destination frame address;
diff --git a/compiler-rt/lib/asan/asan_fuchsia.cpp b/compiler-rt/lib/asan/asan_fuchsia.cpp
index 2b15504123bee7..12625e9d75833d 100644
--- a/compiler-rt/lib/asan/asan_fuchsia.cpp
+++ b/compiler-rt/lib/asan/asan_fuchsia.cpp
@@ -240,6 +240,8 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) {
 // So this doesn't install any atexit hook like on other platforms.
 void InstallAtExitCheckLeaks() {}
 
+void InstallAtForkHandler() {}
+
 }  // namespace __asan
 
 namespace __lsan {
diff --git a/compiler-rt/lib/asan/asan_internal.h b/compiler-rt/lib/asan/asan_internal.h
index 5b97e77882cd67..2944ebe213b5d5 100644
--- a/compiler-rt/lib/asan/asan_internal.h
+++ b/compiler-rt/lib/asan/asan_internal.h
@@ -126,6 +126,7 @@ void *AsanDlSymNext(const char *sym);
 bool HandleDlopenInit();
 
 void InstallAtExitCheckLeaks();
+void InstallAtForkHandler();
 
 #define ASAN_ON_ERROR() \
   if (&__asan_on_error) \
diff --git a/compiler-rt/lib/asan/asan_posix.cpp b/compiler-rt/lib/asan/asan_posix.cpp
index e1f66641617cc1..37fca8aea51511 100644
--- a/compiler-rt/lib/asan/asan_posix.cpp
+++ b/compiler-rt/lib/asan/asan_posix.cpp
@@ -148,6 +148,30 @@ void PlatformTSDDtor(void *tsd) {
 }
 #endif
 
+void InstallAtForkHandler() {
+  auto before = []() {
+    if (CAN_SANITIZE_LEAKS) {
+      __lsan::LockGlobal();
+    }
+    // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and do the
+    // job.
+    __lsan::LockThreads();
+    __lsan::LockAllocator();
+    StackDepotLockAll();
+  };
+  auto after = []() {
+    StackDepotUnlockAll();
+    // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and do the
+    // job.
+    __lsan::UnlockAllocator();
+    __lsan::UnlockThreads();
+    if (CAN_SANITIZE_LEAKS) {
+      __lsan::UnlockGlobal();
+    }
+  };
+  pthread_atfork(before, after, after);
+}
+
 void InstallAtExitCheckLeaks() {
   if (CAN_SANITIZE_LEAKS) {
     if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
diff --git a/compiler-rt/lib/asan/asan_rtl.cpp b/compiler-rt/lib/asan/asan_rtl.cpp
index b28f9f181239b3..a61deed7382b02 100644
--- a/compiler-rt/lib/asan/asan_rtl.cpp
+++ b/compiler-rt/lib/asan/asan_rtl.cpp
@@ -493,6 +493,8 @@ static bool AsanInitInternal() {
     InstallAtExitCheckLeaks();
   }
 
+  InstallAtForkHandler();
+
 #if CAN_SANITIZE_UB
   __ubsan::InitAsPlugin();
 #endif
diff --git a/compiler-rt/lib/asan/asan_win.cpp b/compiler-rt/lib/asan/asan_win.cpp
index d5a30f471e2b0d..f16ce677618e4f 100644
--- a/compiler-rt/lib/asan/asan_win.cpp
+++ b/compiler-rt/lib/asan/asan_win.cpp
@@ -203,6 +203,8 @@ void InitializePlatformInterceptors() {
 
 void InstallAtExitCheckLeaks() {}
 
+void InstallAtForkHandler() {}
+
 void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
   UNIMPLEMENTED();
 }
diff --git a/compiler-rt/lib/hwasan/hwasan.cpp b/compiler-rt/lib/hwasan/hwasan.cpp
index 2f6cb10caf1be6..52780becbdb264 100644
--- a/compiler-rt/lib/hwasan/hwasan.cpp
+++ b/compiler-rt/lib/hwasan/hwasan.cpp
@@ -678,6 +678,8 @@ uptr __hwasan_tag_pointer(uptr p, u8 tag) {
   return AddTagToPointer(p, tag);
 }
 
+u8 __hwasan_get_tag_from_pointer(uptr p) { return GetTagFromPointer(p); }
+
 void __hwasan_handle_longjmp(const void *sp_dst) {
   uptr dst = (uptr)sp_dst;
   // HWASan does not support tagged SP.
diff --git a/compiler-rt/lib/hwasan/hwasan.h b/compiler-rt/lib/hwasan/hwasan.h
index 37ef4822285110..df21375e81671f 100644
--- a/compiler-rt/lib/hwasan/hwasan.h
+++ b/compiler-rt/lib/hwasan/hwasan.h
@@ -104,9 +104,9 @@ static inline void *UntagPtr(const void *tagged_ptr) {
 }
 
 static inline uptr AddTagToPointer(uptr p, tag_t tag) {
-  return InTaggableRegion(p)
-             ? ((p & ~kAddressTagMask) | ((uptr)tag << kAddressTagShift))
-             : p;
+  return InTaggableRegion(p) ? ((p & ~kAddressTagMask) |
+                                ((uptr)(tag & kTagMask) << kAddressTagShift))
+                             : p;
 }
 
 namespace __hwasan {
diff --git a/compiler-rt/lib/hwasan/hwasan_interface_internal.h b/compiler-rt/lib/hwasan/hwasan_interface_internal.h
index e7804cc4903343..8f2f77dad917d2 100644
--- a/compiler-rt/lib/hwasan/hwasan_interface_internal.h
+++ b/compiler-rt/lib/hwasan/hwasan_interface_internal.h
@@ -160,6 +160,9 @@ void __hwasan_tag_memory(uptr p, u8 tag, uptr sz);
 SANITIZER_INTERFACE_ATTRIBUTE
 uptr __hwasan_tag_pointer(uptr p, u8 tag);
 
+SANITIZER_INTERFACE_ATTRIBUTE
+u8 __hwasan_get_tag_from_pointer(uptr p);
+
 SANITIZER_INTERFACE_ATTRIBUTE
 void __hwasan_tag_mismatch(uptr addr, u8 ts);
 
diff --git a/compiler-rt/lib/lsan/lsan.cpp b/compiler-rt/lib/lsan/lsan.cpp
index 6b223603c6a79c..7a27b600f203f7 100644
--- a/compiler-rt/lib/lsan/lsan.cpp
+++ b/compiler-rt/lib/lsan/lsan.cpp
@@ -101,6 +101,7 @@ extern "C" void __lsan_init() {
   InstallDeadlySignalHandlers(LsanOnDeadlySignal);
   InitializeMainThread();
   InstallAtExitCheckLeaks();
+  InstallAtForkHandler();
 
   InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
 
diff --git a/compiler-rt/lib/lsan/lsan.h b/compiler-rt/lib/lsan/lsan.h
index 757edec8e104f9..0074ad5308785c 100644
--- a/compiler-rt/lib/lsan/lsan.h
+++ b/compiler-rt/lib/lsan/lsan.h
@@ -40,6 +40,7 @@ void InitializeInterceptors();
 void ReplaceSystemMalloc();
 void LsanOnDeadlySignal(int signo, void *siginfo, void *context);
 void InstallAtExitCheckLeaks();
+void InstallAtForkHandler();
 
 #define ENSURE_LSAN_INITED        \
   do {                            \
diff --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp
index 8b1af5b629fbce..e24839c984b346 100644
--- a/compiler-rt/lib/lsan/lsan_common.cpp
+++ b/compiler-rt/lib/lsan/lsan_common.cpp
@@ -42,6 +42,9 @@ namespace __lsan {
 // also to protect the global list of root regions.
 static Mutex global_mutex;
 
+void LockGlobal() SANITIZER_ACQUIRE(global_mutex) { global_mutex.Lock(); }
+void UnlockGlobal() SANITIZER_RELEASE(global_mutex) { global_mutex.Unlock(); }
+
 Flags lsan_flags;
 
 void DisableCounterUnderflow() {
diff --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h
index d3e768363e93b9..c598b62105873e 100644
--- a/compiler-rt/lib/lsan/lsan_common.h
+++ b/compiler-rt/lib/lsan/lsan_common.h
@@ -120,6 +120,10 @@ void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads);
 void LockAllocator();
 void UnlockAllocator();
 
+// Lock/unlock global mutext.
+void LockGlobal();
+void UnlockGlobal();
+
 // Returns the address range occupied by the global allocator object.
 void GetAllocatorGlobalRange(uptr *begin, uptr *end);
 // If p points into a chunk that has been allocated to the user, returns its
diff --git a/compiler-rt/lib/lsan/lsan_fuchsia.cpp b/compiler-rt/lib/lsan/lsan_fuchsia.cpp
index 4edac9757a9c49..ba59bc9b71e332 100644
--- a/compiler-rt/lib/lsan/lsan_fuchsia.cpp
+++ b/compiler-rt/lib/lsan/lsan_fuchsia.cpp
@@ -80,6 +80,7 @@ void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {
 // On Fuchsia, leak detection is done by a special hook after atexit hooks.
 // So this doesn't install any atexit hook like on other platforms.
 void InstallAtExitCheckLeaks() {}
+void InstallAtForkHandler() {}
 
 // ASan defines this to check its `halt_on_error` flag.
 bool UseExitcodeOnLeak() { return true; }
diff --git a/compiler-rt/lib/lsan/lsan_posix.cpp b/compiler-rt/lib/lsan/lsan_posix.cpp
index 732b8af2096701..3677f0141a2f02 100644
--- a/compiler-rt/lib/lsan/lsan_posix.cpp
+++ b/compiler-rt/lib/lsan/lsan_posix.cpp
@@ -14,6 +14,8 @@
 #include "sanitizer_common/sanitizer_platform.h"
 
 #if SANITIZER_POSIX
+#  include <pthread.h>
+
 #  include "lsan.h"
 #  include "lsan_allocator.h"
 #  include "lsan_thread.h"
@@ -98,6 +100,22 @@ void InstallAtExitCheckLeaks() {
     Atexit(DoLeakCheck);
 }
 
+void InstallAtForkHandler() {
+  auto before = []() {
+    LockGlobal();
+    LockThreads();
+    LockAllocator();
+    StackDepotLockAll();
+  };
+  auto after = []() {
+    StackDepotUnlockAll();
+    UnlockAllocator();
+    UnlockThreads();
+    UnlockGlobal();
+  };
+  pthread_atfork(before, after, after);
+}
+
 }  // namespace __lsan
 
 #endif  // SANITIZER_POSIX
diff --git a/compiler-rt/test/hwasan/TestCases/tag-ptr.cpp b/compiler-rt/test/hwasan/TestCases/tag-ptr.cpp
new file mode 100644
index 00000000000000..2f00e7913bb155
--- /dev/null
+++ b/compiler-rt/test/hwasan/TestCases/tag-ptr.cpp
@@ -0,0 +1,24 @@
+// RUN: %clangxx_hwasan -O0 %s -o %t && %run %t
+
+#include <assert.h>
+#include <memory>
+#include <sanitizer/hwasan_interface.h>
+#include <set>
+#include <stdio.h>
+
+int main() {
+  auto p = std::make_unique<char>();
+  std::set<void *> ptrs;
+  for (unsigned i = 0;; ++i) {
+    void *ptr = __hwasan_tag_pointer(p.get(), i);
+    if (!ptrs.insert(ptr).second)
+      break;
+    fprintf(stderr, "%p, %u, %u\n", ptr, i, __hwasan_get_tag_from_pointer(ptr));
+    assert(__hwasan_get_tag_from_pointer(ptr) == i);
+  }
+#ifdef __x86_64__
+  assert(ptrs.size() == 8);
+#else
+  assert(ptrs.size() == 256);
+#endif
+}
diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c b/compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c
index cbdf9ee00cff5e..1a52702c5de8c0 100644
--- a/compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c
+++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c
@@ -1,6 +1,6 @@
 // RUN: %clang -O0 %s -o %t && %env_tool_opts=die_after_fork=0 %run %t
 
-// UNSUPPORTED: asan, lsan, hwasan
+// UNSUPPORTED: hwasan
 
 // Forking in multithread environment is unsupported. However we already have
 // some workarounds, and will add more, so this is the test.
diff --git a/compiler-rt/test/sanitizer_common/sanitizer_specific.h b/compiler-rt/test/sanitizer_common/sanitizer_specific.h
index 898899f00e3701..541af18a74979b 100644
--- a/compiler-rt/test/sanitizer_common/sanitizer_specific.h
+++ b/compiler-rt/test/sanitizer_common/sanitizer_specific.h
@@ -31,6 +31,19 @@ static void make_mem_good(void *p, size_t s) {
 static void make_mem_bad(void *p, size_t s) {
   __asan_poison_memory_region(p, s);
 }
+#elif __has_feature(hwaddress_sanitizer)
+#  include <sanitizer/hwasan_interface.h>
+#  include <stdlib.h>
+static void check_mem_is_good(void *p, size_t s) {
+  if (__hwasan_test_shadow(p, s) != -1)
+    abort();
+}
+static void make_mem_good(void *p, size_t s) {
+  __hwasan_tag_memory(p, __hwasan_get_tag_from_pointer(p), s);
+}
+static void make_mem_bad(void *p, size_t s) {
+  __hwasan_tag_memory(p, ~__hwasan_get_tag_from_pointer(p), s);
+}
 #else
 static void check_mem_is_good(void *p, size_t s) {}
 static void make_mem_good(void *p, size_t s) {}

>From 3fd3319b204201b759ffba2d748db1343ce326aa Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Tue, 12 Dec 2023 23:03:02 -0800
Subject: [PATCH 2/4] remove unrelated change

Created using spr 1.3.4
---
 .../test/sanitizer_common/TestCases/Posix/fork_threaded.c     | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c b/compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c
index f27859f815ff91..0d760db169793a 100644
--- a/compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c
+++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c
@@ -56,10 +56,6 @@ NOSAN static void *inchild(void *arg) {
 }
 
 int main(void) {
-#if __has_feature(hwaddress_sanitizer)
-  __hwasan_enable_allocator_tagging();
-#endif
-
   pid_t pid;
 
   pthread_barrier_init(&bar, NULL, 2);

>From 7af834fc25a38ad0050ba8c28df43d548ae89497 Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Wed, 13 Dec 2023 13:40:47 -0800
Subject: [PATCH 3/4] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20ch?=
 =?UTF-8?q?anges=20introduced=20through=20rebase?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.4

[skip ci]
---
 compiler-rt/test/sanitizer_common/sanitizer_specific.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler-rt/test/sanitizer_common/sanitizer_specific.h b/compiler-rt/test/sanitizer_common/sanitizer_specific.h
index 8e94e1782ec888..921ff142f93816 100644
--- a/compiler-rt/test/sanitizer_common/sanitizer_specific.h
+++ b/compiler-rt/test/sanitizer_common/sanitizer_specific.h
@@ -48,7 +48,7 @@ static void make_mem_bad(void *p, size_t s) {
     // tagged memory.
     tag = 1;
   }
-  __hwasan_tag_memory(p, , s);
+  __hwasan_tag_memory(p, tag, s);
   // With misaligned `p` or short granules we can't guarantee tag mismatch.
   if (__hwasan_test_shadow(p, s) != 0)
     abort();

>From f4a9da659690d175345d17b6dc75e397f0fb0079 Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Wed, 13 Dec 2023 14:25:15 -0800
Subject: [PATCH 4/4] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20ch?=
 =?UTF-8?q?anges=20introduced=20through=20rebase?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.4

[skip ci]
---
 compiler-rt/test/sanitizer_common/sanitizer_specific.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler-rt/test/sanitizer_common/sanitizer_specific.h b/compiler-rt/test/sanitizer_common/sanitizer_specific.h
index 759236ab61ef02..99a4dd98c614a1 100644
--- a/compiler-rt/test/sanitizer_common/sanitizer_specific.h
+++ b/compiler-rt/test/sanitizer_common/sanitizer_specific.h
@@ -52,7 +52,7 @@ static void make_mem_bad(void *p, size_t s) {
   // With misaligned `p` or short granules we can't guarantee tag mismatch.
   if (__hwasan_test_shadow(p, s) != 0)
     abort();
-  if (s > 1 && __hwasan_test_shadow(((char*)p) + s - 1, 1) != 0)
+  if (s > 1 && __hwasan_test_shadow(((char *)p) + s - 1, 1) != 0)
     abort();
 }
 #else



More information about the cfe-commits mailing list