Skip to content

Conversation

@plemarquand
Copy link
Contributor

runtimeLibraryPaths, swiftCompilerVersion and targetInfo were all marked as lazy on the UserToolchain class which could lead to race conditions if callers on multiple threads attempted to initialize them simultaneously.

Use an NSLock to guard access while initialization occurs, preventing crashes.

`runtimeLibraryPaths`, `swiftCompilerVersion` and `targetInfo` were all
marked as lazy on the UserToolchain class which could lead to race
conditions if callers on multiple threads attempted to initialize them
simultaneously.

Use an `NSRecursiveLock` to guard access while initialization occurs,
preventing crashes.
@plemarquand plemarquand force-pushed the thread-safe-lazy-usertoolchain branch from 753bcfc to 274f115 Compare November 10, 2025 22:24
@plemarquand
Copy link
Contributor Author

@swift-ci please test

public let librarySearchPaths: [AbsolutePath]

/// Lock for thread-safe access to lazy properties (recursive to handle property dependencies)
private let lazyPropertiesLock = NSRecursiveLock()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directly using NSLock/NSRecursiveLock is not the recommended pattern in modern Swift, instead you'll want to use an abstraction like Swift Build's LockedValue. In SwiftPM you can use ThreadSafeBox from TSCBasic.

If you want to use a single lock for multiple values to avoid a proliferation of fine-grained locks, you can define a struct to hold the values, and then guard access to the overall struct through the wrapper, rather than using a separate lock for each value.

Later, once we can increase our deployment target to macOS 15, we can replace LockedValue/ThreadSafeBox with Mutex from the Swift Standard Library.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I figured these could be replaced with Mutex once we're ready to adopt but didn't know about ThreadSafeBox's used in SwiftPM. I've updated the implementation accordingly.

@plemarquand
Copy link
Contributor Author

@swift-ci please test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants