[rtsan][Apple] Add interceptor for _os_nospin_lock_lock (#131034)
Follows the discussion here: https://github.com/llvm/llvm-project/pull/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 481a55a3d9645a6bc1540d326319b78ad8ed8db1)
This commit is contained in:
parent
4370072022
commit
f811c7df0a
@ -30,6 +30,12 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
typedef int32_t OSSpinLock;
|
typedef int32_t OSSpinLock;
|
||||||
void OSSpinLockLock(volatile OSSpinLock *__lock);
|
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
|
#endif // TARGET_OS_MAC
|
||||||
|
|
||||||
@ -642,6 +648,11 @@ INTERCEPTOR(void, os_unfair_lock_lock, os_unfair_lock_t lock) {
|
|||||||
__rtsan_notify_intercepted_call("os_unfair_lock_lock");
|
__rtsan_notify_intercepted_call("os_unfair_lock_lock");
|
||||||
return REAL(os_unfair_lock_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 \
|
#define RTSAN_MAYBE_INTERCEPT_OS_UNFAIR_LOCK_LOCK \
|
||||||
INTERCEPT_FUNCTION(os_unfair_lock_lock)
|
INTERCEPT_FUNCTION(os_unfair_lock_lock)
|
||||||
#else
|
#else
|
||||||
|
@ -1058,6 +1058,25 @@ TEST(TestRtsanInterceptors, OsUnfairLockLockDiesWhenRealtime) {
|
|||||||
ExpectRealtimeDeath(Func, "os_unfair_lock_lock");
|
ExpectRealtimeDeath(Func, "os_unfair_lock_lock");
|
||||||
ExpectNonRealtimeSurvival(Func);
|
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
|
||||||
|
|
||||||
#if SANITIZER_LINUX
|
#if SANITIZER_LINUX
|
||||||
|
Loading…
x
Reference in New Issue
Block a user