Skip to content

Commit 2556643

Browse files
committed
Fixup Usage of pthread Mutexes on macOS
Did you know that pthread_mutex_init can _fail_? On macOS, the value of PTHREAD_MUTEX_INITIALIZER is not just zeroes - there's optional signature bits in there. POSIX says that you're allowed to check for those signature bits in the API and issue EINVAL if they don't match. By default, pthread_mutex_t() in swift will zero-fill through those signature bits, which results in an invalid mutex variable - even WRT pthread_mutex_init. Once that fails, all subsequent calls to lock and unlock will fail too and leave all of your critical sections completely unguarded. Thank you POSIX On Linuxes this is (often) not the case, and they tend to just use zeroes here, don't check the signature, or both. This allows compilers to allocate lock variables in .bss, which is kinda neat. So, on macOS, we need to install those signature bits, BUT Swift cannot import PTHREAD_MUTEX_INITIALIZER since it's a non-trivial macro that uses brace initialization. Really what we care about is just the signature bits, so we'll install those by hand.
1 parent 1217497 commit 2556643

File tree

1 file changed

+12
-1
lines changed

1 file changed

+12
-1
lines changed

Sources/SwiftSyntax/PlatformMutex.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,18 @@ struct PlatformMutex {
3737
let storage = allocator.allocate(Primitive.self, count: 1).baseAddress!
3838
storage.initialize(to: Primitive())
3939
#if canImport(Darwin) || canImport(Glibc)
40-
pthread_mutex_init(storage, nil)
40+
#if canImport(Darwin)
41+
// HACK: On Darwin, the value of PTHREAD_MUTEX_INITIALIZER installs
42+
// signature bits into the mutex that are later checked by other aspects
43+
// of the mutex API. This is a completely optional POSIX-ism that most
44+
// Linuxes don't implement - often so that (global) lock variables can be
45+
// stuck in .bss. Swift doesn't know how to import
46+
// PTHREAD_MUTEX_INITIALIZER, so we'll replicate its signature-installing
47+
// magic with the bit it can import.
48+
storage.pointee.__sig = Int(_PTHREAD_MUTEX_SIG_init)
49+
#endif
50+
let result = pthread_mutex_init(storage, nil)
51+
assert(result == 0)
4152
#elseif canImport(WinSDK)
4253
InitializeSRWLock(storage)
4354
#endif

0 commit comments

Comments
 (0)