|
|
| Previous ID |
SR-192 |
| Radar |
None |
| Original Reporter |
@mikeash |
| Type |
Bug |
| Status |
Closed |
| Resolution |
Done |
Additional Detail from JIRA
|
|
| Votes |
8 |
| Component/s |
|
| Labels |
Bug, Runtime |
| Assignee |
@glessard |
| Priority |
Medium |
md5: e84790d9452452d03d108981ba9ce226
Issue Description:
The current implementation of weak references has a race condition when multiple threads read the same weak reference to a deallocating object simultaneously. Since this is semantically read-only access (even if writing occurs under the hood), this should be made safe.
The bug itself lies in the swift_weakLoadStrong function. If two threads simultaneously enter this function with the same weak reference and object->refCount.isDeallocating() is true, the threads will race. This can result in calling swift_unownedRelease() twice resulting in a double-free or worse, or it could result in one thread calling swift_tryRetain() on a deallocated object.
Here is a test case which demonstrates the problem:
import Foundation
class Target {}
class WeakHolder {
weak var weak: Target?
}
for i in 0..<1000000 {
print(i)
let holder = WeakHolder()
holder.weak = Target()
dispatch_async(dispatch_get_global_queue(0, 0), {
let _ = holder.weak
})
dispatch_async(dispatch_get_global_queue(0, 0), {
let _ = holder.weak
})
}
Additional Detail from JIRA
md5: e84790d9452452d03d108981ba9ce226
Issue Description:
The current implementation of weak references has a race condition when multiple threads read the same weak reference to a deallocating object simultaneously. Since this is semantically read-only access (even if writing occurs under the hood), this should be made safe.
The bug itself lies in the
swift_weakLoadStrongfunction. If two threads simultaneously enter this function with the same weak reference and object->refCount.isDeallocating() is true, the threads will race. This can result in calling swift_unownedRelease() twice resulting in a double-free or worse, or it could result in one thread calling swift_tryRetain() on a deallocated object.Here is a test case which demonstrates the problem: