[compiler-rt] 64453c8 - rtsan: Support free_sized and free_aligned_sized from C23 (#145085)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 9 10:37:03 PDT 2025


Author: Justin King
Date: 2025-07-09T10:36:59-07:00
New Revision: 64453c802eca9bd839e2fb43d1a6a1b0e7c83e58

URL: https://github.com/llvm/llvm-project/commit/64453c802eca9bd839e2fb43d1a6a1b0e7c83e58
DIFF: https://github.com/llvm/llvm-project/commit/64453c802eca9bd839e2fb43d1a6a1b0e7c83e58.diff

LOG: rtsan: Support free_sized and free_aligned_sized from C23 (#145085)

Adds support to RTSan for `free_sized` and `free_aligned_sized` from
C23.

Other sanitizers will be handled with their own separate PRs.

For https://github.com/llvm/llvm-project/issues/144435

Signed-off-by: Justin King <jcking at google.com>

Added: 
    

Modified: 
    compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
    compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp
    compiler-rt/test/sanitizer_common/TestCases/Linux/free_aligned_sized.c
    compiler-rt/test/sanitizer_common/TestCases/Linux/free_sized.c

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
index 9f9ffd4313810..a9d864e9fe926 100644
--- a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
@@ -869,6 +869,48 @@ INTERCEPTOR(void, free, void *ptr) {
   return REAL(free)(ptr);
 }
 
+#if SANITIZER_INTERCEPT_FREE_SIZED
+INTERCEPTOR(void, free_sized, void *ptr, SIZE_T size) {
+  if (DlsymAlloc::PointerIsMine(ptr))
+    return DlsymAlloc::Free(ptr);
+
+  // According to the C and C++ standard, freeing a nullptr is guaranteed to be
+  // a no-op (and thus real-time safe). This can be confirmed for looking at
+  // __libc_free in the glibc source.
+  if (ptr != nullptr)
+    __rtsan_notify_intercepted_call("free_sized");
+
+  if (REAL(free_sized))
+    return REAL(free_sized)(ptr, size);
+  return REAL(free)(ptr);
+}
+#define RTSAN_MAYBE_INTERCEPT_FREE_SIZED INTERCEPT_FUNCTION(free_sized)
+#else
+#define RTSAN_MAYBE_INTERCEPT_FREE_SIZED
+#endif
+
+#if SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED
+INTERCEPTOR(void, free_aligned_sized, void *ptr, SIZE_T alignment,
+            SIZE_T size) {
+  if (DlsymAlloc::PointerIsMine(ptr))
+    return DlsymAlloc::Free(ptr);
+
+  // According to the C and C++ standard, freeing a nullptr is guaranteed to be
+  // a no-op (and thus real-time safe). This can be confirmed for looking at
+  // __libc_free in the glibc source.
+  if (ptr != nullptr)
+    __rtsan_notify_intercepted_call("free_aligned_sized");
+
+  if (REAL(free_aligned_sized))
+    return REAL(free_aligned_sized)(ptr, alignment, size);
+  return REAL(free)(ptr);
+}
+#define RTSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED                               \
+  INTERCEPT_FUNCTION(free_aligned_sized)
+#else
+#define RTSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED
+#endif
+
 INTERCEPTOR(void *, malloc, SIZE_T size) {
   if (DlsymAlloc::Use())
     return DlsymAlloc::Allocate(size);
@@ -1493,6 +1535,8 @@ INTERCEPTOR(INT_TYPE_SYSCALL, syscall, INT_TYPE_SYSCALL number, ...) {
 void __rtsan::InitializeInterceptors() {
   INTERCEPT_FUNCTION(calloc);
   INTERCEPT_FUNCTION(free);
+  RTSAN_MAYBE_INTERCEPT_FREE_SIZED;
+  RTSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED;
   INTERCEPT_FUNCTION(malloc);
   INTERCEPT_FUNCTION(realloc);
   INTERCEPT_FUNCTION(reallocf);

diff  --git a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp
index 2ee35555c24de..26a3b252d3b6b 100644
--- a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp
+++ b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp
@@ -63,6 +63,14 @@
 #define MAYBE_APPEND_64(func) func
 #endif
 
+#if SANITIZER_INTERCEPT_FREE_SIZED
+extern "C" void free_sized(void *ptr, size_t size);
+#endif
+
+#if SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED
+extern "C" void free_aligned_sized(void *ptr, size_t alignment, size_t size);
+#endif
+
 using namespace testing;
 using namespace rtsan_testing;
 using namespace std::chrono_literals;
@@ -148,7 +156,6 @@ TEST(TestRtsanInterceptors, AlignedAllocDiesWhenRealtime) {
   }
 }
 
-// free_sized and free_aligned_sized (both C23) are not yet supported
 TEST(TestRtsanInterceptors, FreeDiesWhenRealtime) {
   void *ptr_1 = malloc(1);
   void *ptr_2 = malloc(1);
@@ -160,11 +167,55 @@ TEST(TestRtsanInterceptors, FreeDiesWhenRealtime) {
   ASSERT_NE(nullptr, ptr_2);
 }
 
+#if SANITIZER_INTERCEPT_FREE_SIZED
+TEST(TestRtsanInterceptors, FreeSizedDiesWhenRealtime) {
+  void *ptr_1 = malloc(1);
+  void *ptr_2 = malloc(1);
+  ExpectRealtimeDeath([ptr_1]() { free_sized(ptr_1, 1); }, "free_sized");
+  ExpectNonRealtimeSurvival([ptr_2]() { free_sized(ptr_2, 1); });
+
+  // Prevent malloc/free pair being optimised out
+  ASSERT_NE(nullptr, ptr_1);
+  ASSERT_NE(nullptr, ptr_2);
+}
+#endif
+
+#if SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED
+TEST(TestRtsanInterceptors, FreeAlignedSizedDiesWhenRealtime) {
+  if (ALIGNED_ALLOC_AVAILABLE()) {
+    void *ptr_1 = aligned_alloc(16, 32);
+    void *ptr_2 = aligned_alloc(16, 32);
+    ExpectRealtimeDeath([ptr_1]() { free_aligned_sized(ptr_1, 16, 32); },
+                        "free_aligned_sized");
+    ExpectNonRealtimeSurvival([ptr_2]() { free_aligned_sized(ptr_2, 16, 32); });
+
+    // Prevent malloc/free pair being optimised out
+    ASSERT_NE(nullptr, ptr_1);
+    ASSERT_NE(nullptr, ptr_2);
+  }
+}
+#endif
+
 TEST(TestRtsanInterceptors, FreeSurvivesWhenRealtimeIfArgumentIsNull) {
   RealtimeInvoke([]() { free(NULL); });
   ExpectNonRealtimeSurvival([]() { free(NULL); });
 }
 
+#if SANITIZER_INTERCEPT_FREE_SIZED
+TEST(TestRtsanInterceptors, FreeSizedSurvivesWhenRealtimeIfArgumentIsNull) {
+  RealtimeInvoke([]() { free_sized(NULL, 0); });
+  ExpectNonRealtimeSurvival([]() { free_sized(NULL, 0); });
+}
+#endif
+
+#if SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED
+TEST(TestRtsanInterceptors,
+     FreeAlignedSizedSurvivesWhenRealtimeIfArgumentIsNull) {
+  RealtimeInvoke([]() { free_aligned_sized(NULL, 0, 0); });
+  ExpectNonRealtimeSurvival([]() { free_aligned_sized(NULL, 0, 0); });
+}
+#endif
+
 TEST(TestRtsanInterceptors, PosixMemalignDiesWhenRealtime) {
   auto Func = []() {
     void *ptr;

diff  --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/free_aligned_sized.c b/compiler-rt/test/sanitizer_common/TestCases/Linux/free_aligned_sized.c
index dc11e7fa5e9b3..15b1a43f596e8 100644
--- a/compiler-rt/test/sanitizer_common/TestCases/Linux/free_aligned_sized.c
+++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/free_aligned_sized.c
@@ -1,9 +1,11 @@
 // RUN: %clang -std=c23 -O0 %s -o %t && %run %t
-// UNSUPPORTED: asan, hwasan, rtsan, ubsan
+// UNSUPPORTED: asan, hwasan, ubsan
 
 #include <stddef.h>
 #include <stdlib.h>
 
+extern void *aligned_alloc(size_t alignment, size_t size);
+
 extern void free_aligned_sized(void *p, size_t alignment, size_t size);
 
 int main() {

diff  --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/free_sized.c b/compiler-rt/test/sanitizer_common/TestCases/Linux/free_sized.c
index 7a993d481bc5a..d8ec1e8b364b6 100644
--- a/compiler-rt/test/sanitizer_common/TestCases/Linux/free_sized.c
+++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/free_sized.c
@@ -1,11 +1,9 @@
 // RUN: %clang -std=c23 -O0 %s -o %t && %run %t
-// UNSUPPORTED: asan, hwasan, rtsan, ubsan
+// UNSUPPORTED: asan, hwasan, ubsan
 
 #include <stddef.h>
 #include <stdlib.h>
 
-extern void *aligned_alloc(size_t alignment, size_t size);
-
 extern void free_sized(void *p, size_t size);
 
 int main() {


        


More information about the llvm-commits mailing list