Skip to content

Commit fe1dede

Browse files
committed
SwiftSyntax: avoid a possible deadlock situtation
Access the consumers list in the DiagnosticsEngine directly to the storage rather than the accessor. This prevents a possible issue with invalid usage of `dispatch_sync`. It has been observed on Windows (and Linux) that there are times where dispatch would trigger an assertion that `dispatch_sync` was called on a queue owned by the current thread. It is possible that a thread of execution would invoke the `consumers` setter, which enqueues a block with barrier semantics. Because the task is async, the `DiagnosticsEngine` instance has the reference count incremented. The caller then continues execution immediately (due to the async nature) and then proceeds to terminate. The `DiagnosticEngine`'s instance is now effectively owned by the queue. When the enqueued block executes, the `deinit` invocation will execute on the thread owning the `consumersQueue`. The `deinit` then proceeds to access the `consumers` through a `dispatch_sync`, resulting in a deadlock. This issue was uncovered by running the swift-format testsuite on Windows. Special thanks to @allevato for his invaluable discussion and insight into what may be occurring here.
1 parent 593d01f commit fe1dede

File tree

1 file changed

+1
-1
lines changed

1 file changed

+1
-1
lines changed

Sources/SwiftSyntax/DiagnosticEngine.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public class DiagnosticEngine {
9595

9696
/// Tells each consumer to finalize their diagnostic output.
9797
deinit {
98-
for consumer in consumers {
98+
for consumer in _consumers {
9999
consumer.finalize()
100100
}
101101
}

0 commit comments

Comments
 (0)