[RTSan][Darwin] Adjust OSSpinLock/_os_nospin_lock interceptor and tests (#132867)

These changes align with these lock types and allows builds and tests to
pass with various SDKS.

rdar://147067322
This commit is contained in:
thetruestblue 2025-04-18 11:25:31 -07:00 committed by GitHub
parent 3191cfd824
commit 7cc4472037
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 32 additions and 45 deletions

View File

@ -21,24 +21,6 @@
#include "rtsan/rtsan.h"
#if SANITIZER_APPLE
#if TARGET_OS_MAC
// On MacOS OSSpinLockLock is deprecated and no longer present in the headers,
// but the symbol still exists on the system. Forward declare here so we
// don't get compilation errors.
#include <stdint.h>
extern "C" {
typedef int32_t OSSpinLock;
void OSSpinLockLock(volatile OSSpinLock *__lock);
// A pointer to this type is in the interface for `_os_nospin_lock_lock`, but
// it's an internal implementation detail of `os/lock.c` on Darwin, and
// therefore not available in any headers. As a workaround, we forward declare
// it here, which is enough to facilitate interception of _os_nospin_lock_lock.
struct _os_nospin_lock_s;
using _os_nospin_lock_t = _os_nospin_lock_s *;
}
#endif // TARGET_OS_MAC
#include <libkern/OSAtomic.h>
#include <os/lock.h>
#endif // SANITIZER_APPLE
@ -717,26 +699,35 @@ INTERCEPTOR(mode_t, umask, mode_t cmask) {
#pragma clang diagnostic push
// OSSpinLockLock is deprecated, but still in use in libc++
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#undef OSSpinLockLock
INTERCEPTOR(void, OSSpinLockLock, volatile OSSpinLock *lock) {
__rtsan_notify_intercepted_call("OSSpinLockLock");
return REAL(OSSpinLockLock)(lock);
}
#pragma clang diagnostic pop
#define RTSAN_MAYBE_INTERCEPT_OSSPINLOCKLOCK INTERCEPT_FUNCTION(OSSpinLockLock)
#else
#define RTSAN_MAYBE_INTERCEPT_OSSPINLOCKLOCK
#endif // SANITIZER_APPLE
#if SANITIZER_APPLE
// _os_nospin_lock_lock may replace OSSpinLockLock due to deprecation macro.
typedef volatile OSSpinLock *_os_nospin_lock_t;
INTERCEPTOR(void, _os_nospin_lock_lock, _os_nospin_lock_t lock) {
__rtsan_notify_intercepted_call("_os_nospin_lock_lock");
return REAL(_os_nospin_lock_lock)(lock);
}
#pragma clang diagnostic pop // "-Wdeprecated-declarations"
#endif // SANITIZER_APPLE
#if SANITIZER_APPLE
INTERCEPTOR(void, os_unfair_lock_lock, os_unfair_lock_t lock) {
__rtsan_notify_intercepted_call("os_unfair_lock_lock");
return REAL(os_unfair_lock_lock)(lock);
}
INTERCEPTOR(void, _os_nospin_lock_lock, _os_nospin_lock_t lock) {
__rtsan_notify_intercepted_call("_os_nospin_lock_lock");
return REAL(_os_nospin_lock_lock)(lock);
}
#define RTSAN_MAYBE_INTERCEPT_OS_UNFAIR_LOCK_LOCK \
INTERCEPT_FUNCTION(os_unfair_lock_lock)
#else

View File

@ -1126,10 +1126,18 @@ TEST(TestRtsanInterceptors, PthreadJoinDiesWhenRealtime) {
}
#if SANITIZER_APPLE
#pragma clang diagnostic push
// OSSpinLockLock is deprecated, but still in use in libc++
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#undef OSSpinLockLock
extern "C" {
typedef int32_t OSSpinLock;
void OSSpinLockLock(volatile OSSpinLock *__lock);
// _os_nospin_lock_lock may replace OSSpinLockLock due to deprecation macro.
typedef volatile OSSpinLock *_os_nospin_lock_t;
void _os_nospin_lock_lock(_os_nospin_lock_t lock);
}
TEST(TestRtsanInterceptors, OsSpinLockLockDiesWhenRealtime) {
auto Func = []() {
OSSpinLock spin_lock{};
@ -1138,7 +1146,14 @@ TEST(TestRtsanInterceptors, OsSpinLockLockDiesWhenRealtime) {
ExpectRealtimeDeath(Func, "OSSpinLockLock");
ExpectNonRealtimeSurvival(Func);
}
#pragma clang diagnostic pop
TEST(TestRtsanInterceptors, OsNoSpinLockLockDiesWhenRealtime) {
OSSpinLock lock{};
auto Func = [&]() { _os_nospin_lock_lock(&lock); };
ExpectRealtimeDeath(Func, "_os_nospin_lock_lock");
ExpectNonRealtimeSurvival(Func);
}
#pragma clang diagnostic pop //"-Wdeprecated-declarations"
TEST(TestRtsanInterceptors, OsUnfairLockLockDiesWhenRealtime) {
auto Func = []() {
@ -1148,26 +1163,7 @@ TEST(TestRtsanInterceptors, OsUnfairLockLockDiesWhenRealtime) {
ExpectRealtimeDeath(Func, "os_unfair_lock_lock");
ExpectNonRealtimeSurvival(Func);
}
// We intercept _os_nospin_lock_lock because it's the internal
// locking mechanism for MacOS's atomic implementation for data
// types that are larger than the hardware's maximum lock-free size.
// However, it's a private implementation detail and not visible in any headers,
// so we must duplicate the required type definitions to forward declaration
// what we need here.
extern "C" {
struct _os_nospin_lock_s {
unsigned int oul_value;
};
void _os_nospin_lock_lock(_os_nospin_lock_s *);
}
TEST(TestRtsanInterceptors, OsNoSpinLockLockDiesWhenRealtime) {
_os_nospin_lock_s lock{};
auto Func = [&]() { _os_nospin_lock_lock(&lock); };
ExpectRealtimeDeath(Func, "_os_nospin_lock_lock");
ExpectNonRealtimeSurvival(Func);
}
#endif
#endif // SANITIZER_APPLE
#if SANITIZER_LINUX
TEST(TestRtsanInterceptors, SpinLockLockDiesWhenRealtime) {