Skip to content

Commit 2453cd2

Browse files
davidtrevelyanthetruestblue
authored andcommitted
[rtsan][Apple] Add interceptor for _os_nospin_lock_lock (llvm#131034)
Follows the discussion here: llvm#129309 Recently, the test `TestRtsan.AccessingALargeAtomicVariableDiesWhenRealtime` has been failing on newer MacOS versions, because the internal locking mechanism in `std::atomic<T>::load` (for types `T` that are larger than the hardware lock-free limit), has changed to a function that wasn't being intercepted by rtsan. This PR introduces an interceptor for `_os_nospin_lock_lock`, which is the new internal locking mechanism. _Note: we'd probably do well to introduce interceptors for `_os_nospin_lock_unlock` (and `os_unfair_lock_unlock`) too, which also appear to have blocking implementations. This can follow in a separate PR._ (cherry picked from commit 481a55a)
1 parent ab0074f commit 2453cd2

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@
3030
extern "C" {
3131
typedef int32_t OSSpinLock;
3232
void OSSpinLockLock(volatile OSSpinLock *__lock);
33+
// A pointer to this type is in the interface for `_os_nospin_lock_lock`, but
34+
// it's an internal implementation detail of `os/lock.c` on Darwin, and
35+
// therefore not available in any headers. As a workaround, we forward declare
36+
// it here, which is enough to facilitate interception of _os_nospin_lock_lock.
37+
struct _os_nospin_lock_s;
38+
using _os_nospin_lock_t = _os_nospin_lock_s *;
3339
}
3440
#endif // TARGET_OS_MAC
3541

@@ -642,6 +648,11 @@ INTERCEPTOR(void, os_unfair_lock_lock, os_unfair_lock_t lock) {
642648
__rtsan_notify_intercepted_call("os_unfair_lock_lock");
643649
return REAL(os_unfair_lock_lock)(lock);
644650
}
651+
652+
INTERCEPTOR(void, _os_nospin_lock_lock, _os_nospin_lock_t lock) {
653+
__rtsan_notify_intercepted_call("_os_nospin_lock_lock");
654+
return REAL(_os_nospin_lock_lock)(lock);
655+
}
645656
#define RTSAN_MAYBE_INTERCEPT_OS_UNFAIR_LOCK_LOCK \
646657
INTERCEPT_FUNCTION(os_unfair_lock_lock)
647658
#else

compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -1058,6 +1058,25 @@ TEST(TestRtsanInterceptors, OsUnfairLockLockDiesWhenRealtime) {
10581058
ExpectRealtimeDeath(Func, "os_unfair_lock_lock");
10591059
ExpectNonRealtimeSurvival(Func);
10601060
}
1061+
1062+
// We intercept _os_nospin_lock_lock because it's the internal
1063+
// locking mechanism for MacOS's atomic implementation for data
1064+
// types that are larger than the hardware's maximum lock-free size.
1065+
// However, it's a private implementation detail and not visible in any headers,
1066+
// so we must duplicate the required type definitions to forward declaration
1067+
// what we need here.
1068+
extern "C" {
1069+
struct _os_nospin_lock_s {
1070+
unsigned int oul_value;
1071+
};
1072+
void _os_nospin_lock_lock(_os_nospin_lock_s *);
1073+
}
1074+
TEST(TestRtsanInterceptors, OsNoSpinLockLockDiesWhenRealtime) {
1075+
_os_nospin_lock_s lock{};
1076+
auto Func = [&]() { _os_nospin_lock_lock(&lock); };
1077+
ExpectRealtimeDeath(Func, "_os_nospin_lock_lock");
1078+
ExpectNonRealtimeSurvival(Func);
1079+
}
10611080
#endif
10621081

10631082
#if SANITIZER_LINUX

0 commit comments

Comments
 (0)