New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SR-6543] Data race when passing copies of values across threads. #49093
Comments
@milseman, for |
CC Lance (JIRA User) @lorentey |
These are great test cases. These are the steps in the simple test case from the bug description 1. `array` refcount is incremented when `copy2` is captured. 2. `array` is captured by an escaping closure. 3. The last (unsynchronized) call to array.append is executed first. 3a. The append performs an unsynchronized read of the shared buffer to copy it into a new unique buffer. 4. `array` goes out of local scope, decrementing the refcount and becoming unique. 5. The synchronized closure runs. 5a. The original `array` buffer is now unique, so no copy is done. 5b. The closure writes to the original `array` buffer. This is an unsynchronized write-after-read. I talked to Kuba, and it's almost certainly: the same thing as I looked into this long enough to feel pretty sure I understand the Also, incidentally, when I decompose compilation into separate |
Aha!!! Finally I see the "problem". In 4.0.3 this part of the array copy gets inlined into user code. On master, it is no longer being inlined: %59 = load %52 : $*Builtin.BridgeObject // user: %60 %67 = struct $Int (%66 : $Builtin.Int64) // user: %69 |
There is a race even if the release is not executed: SR-6604 |
I disagree with aschwaighofer@apple.com (JIRA User)'s comment above about there being a race in the code. |
Yes, Andrew is right there is no race assuming properly fenced library calls are used. If they weren't there is a language level race regardless of whether an Array or a plain value type is used that is my point in SR-6604. |
aschwaighofer@apple.com (JIRA User), Minor addendum to the steps above. 2. `array` is captured by an escaping closure.
... 3a. The append performs an unsynchronized read of the shared buffer to copy it into a new unique buffer. 4. `array` goes out of local scope, decrementing the refcount and becoming unique. 5. The synchronized closure runs. [There is no memory fence here, at least not according to TSAN's semantics] Hence the WAR race. TSAN needs to recognize the uniqueness-causing-release as a synchronization point (full fence)] Note that in reality, the hardware is probably executing many fences, but TSAN only models semantic fences that the user can rely on. |
@atrick aschwaighofer@apple.com (JIRA User) Can this issue be closed? I tested the code in the description with several recent Xcode releases (9.2/Swift 4.0, 9.4/Swift 4.1, 10.1/Swift 4.2, 10.2/Swift 5.0), and Xcode 9.2/Swift 4.0 seems to be the last release where the Thread Sanitizer finds an issue. This seems to match what @atrick wrote above: "In 4.0.3 this part of the array copy gets inlined into user code. On master, it is no longer being inlined" I'm not sure I follow your discussion but it looks like you see this as a TSAN issue and not a Swift issue anyway. |
[EDIT] If my original JIRA comments are correct, then TSAN actually needs to consider a "release" operation as synchronizing on the released object conditionally at runtime when its refcount reaches one. |
Yes, let's have a TSan bug for this. Note that we don't recommend/support running TSan under -O because the diagnostic reports can be hard to understand. But we still shouldn't have false positives in this case. |
To reproduce it on master, I think you'd need to use `@inline(__always)` or hack up your own CoW data type and make sure the important code path is inlined. |
@atrick Thank you for clarifying this for me. |
Attachment: Download
Environment
Xcode 9.2 (9C40b)
Swift 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2)
Additional Detail from JIRA
md5: 48a81342e68c16da71cc9c10a944287b
relates to:
Issue Description:
Consider the following code:
A data race is detected by the thread-sanitizer when the code is compiled with -O.
Please find attached some additional examples where the issue arises (SwiftDataRaceSample.swift).
This issue is very problematic when you want to expose a value type as a public property of a thread-safe class, as shown in the attached sample code.
Related discussion: https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20171204/006693.html
The text was updated successfully, but these errors were encountered: