Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
53 changes: 52 additions & 1 deletion compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down
Loading