Skip to content

Commit c87309e

Browse files
committed
[test] Tests for weak reference read-read thread safety
Dispatch-based tests exist because (on OS X) they are more likely to encounter the race condition than `StdlibUnitTest`'s `runRaceTest()` is.
1 parent 94a9c51 commit c87309e

File tree

2 files changed

+233
-0
lines changed

2 files changed

+233
-0
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// RUN: %target-run-simple-swift
2+
// REQUIRES: executable_test
3+
4+
// REQUIRES: objc_interop
5+
6+
import StdlibUnittest
7+
8+
// Also import modules which are used by StdlibUnittest internally. This
9+
// workaround is needed to link all required libraries in case we compile
10+
// StdlibUnittest with -sil-serialize-all.
11+
import SwiftPrivate
12+
#if _runtime(_ObjC)
13+
import ObjectiveC
14+
#endif
15+
16+
import Dispatch
17+
18+
let iterations = 200_000
19+
20+
class Thing {}
21+
22+
class WBox<T: AnyObject> {
23+
weak var wref: T?
24+
init(_ ref: T) { self.wref = ref }
25+
init() { self.wref = nil }
26+
}
27+
28+
let WeakReferenceRaceTests = TestSuite("WeakReferenceRaceTests")
29+
30+
WeakReferenceRaceTests.test("class instance property [SR-192] (copy)") {
31+
let q = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT)!
32+
33+
// Capture a weak reference via its container object
34+
// "https://bugs.swift.org/browse/SR-192"
35+
for i in 1...iterations {
36+
let box = WBox(Thing())
37+
let closure = {
38+
let nbox = WBox<Thing>()
39+
nbox.wref = box.wref
40+
_blackHole(nbox)
41+
}
42+
43+
dispatch_async(q, closure)
44+
dispatch_async(q, closure)
45+
}
46+
47+
dispatch_barrier_sync(q) {}
48+
}
49+
50+
WeakReferenceRaceTests.test("class instance property [SR-192] (load)") {
51+
let q = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT)!
52+
53+
// Capture a weak reference via its container object
54+
// "https://bugs.swift.org/browse/SR-192"
55+
for i in 1...iterations {
56+
let box = WBox(Thing())
57+
let closure = {
58+
if let ref = box.wref {
59+
_blackHole(ref)
60+
}
61+
}
62+
63+
dispatch_async(q, closure)
64+
dispatch_async(q, closure)
65+
}
66+
67+
dispatch_barrier_sync(q) {}
68+
}
69+
70+
WeakReferenceRaceTests.test("direct capture (copy)") {
71+
let q = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT)!
72+
73+
// Capture a weak reference directly in multiple closures
74+
for i in 1...iterations {
75+
weak var wref = Thing()
76+
let closure = {
77+
let nbox = WBox<Thing>()
78+
nbox.wref = wref
79+
_blackHole(nbox)
80+
}
81+
82+
dispatch_async(q, closure)
83+
dispatch_async(q, closure)
84+
}
85+
86+
dispatch_barrier_sync(q) {}
87+
}
88+
89+
WeakReferenceRaceTests.test("direct capture (load)") {
90+
let q = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT)!
91+
92+
// Capture a weak reference directly in multiple closures
93+
for i in 1...iterations {
94+
weak var wref = Thing()
95+
let closure = {
96+
if let ref = wref {
97+
_blackHole(ref)
98+
}
99+
}
100+
101+
dispatch_async(q, closure)
102+
dispatch_async(q, closure)
103+
}
104+
105+
dispatch_barrier_sync(q) {}
106+
}
107+
108+
runAllTests()
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// RUN: %target-run-simple-swift
2+
// REQUIRES: executable_test
3+
4+
import StdlibUnittest
5+
6+
// Also import modules which are used by StdlibUnittest internally. This
7+
// workaround is needed to link all required libraries in case we compile
8+
// StdlibUnittest with -sil-serialize-all.
9+
import SwiftPrivate
10+
#if _runtime(_ObjC)
11+
import ObjectiveC
12+
#endif
13+
14+
let iterations = 1_000
15+
16+
class Thing {}
17+
18+
class WBox<T: AnyObject> {
19+
weak var wref: T?
20+
init(_ ref: T) { self.wref = ref }
21+
init() { self.wref = nil }
22+
}
23+
24+
class WeakReferenceRaceData {
25+
let closure: () -> Void
26+
init(_ closure: () -> Void) {
27+
self.closure = closure
28+
}
29+
}
30+
31+
protocol WeakReferenceRaceTest: RaceTestWithPerTrialData {
32+
associatedtype RaceData = WeakReferenceRaceData
33+
associatedtype ThreadLocalData = Void
34+
associatedtype Observation = Observation1UInt
35+
}
36+
37+
extension WeakReferenceRaceTest {
38+
func makeThreadLocalData() -> Void {
39+
return ()
40+
}
41+
42+
func thread1(
43+
_ raceData: WeakReferenceRaceData,
44+
_ threadLocalData: inout Void
45+
) -> Observation1UInt {
46+
raceData.closure()
47+
// The trial succeeds by completing without crashing
48+
return Observation1UInt(0)
49+
}
50+
51+
func evaluateObservations(
52+
_ observations: [Observation1UInt],
53+
_ sink: (RaceTestObservationEvaluation) -> Void
54+
) {
55+
sink(evaluateObservationsAllEqual(observations))
56+
}
57+
}
58+
59+
let WeakReferenceRaceTests = TestSuite("WeakReferenceRaceTests")
60+
61+
struct RaceTest_instancePropertyCopy: WeakReferenceRaceTest {
62+
func makeRaceData() -> WeakReferenceRaceData {
63+
// Capture a weak reference via its container object
64+
// "https://bugs.swift.org/browse/SR-192"
65+
let box = WBox(Thing())
66+
return WeakReferenceRaceData {
67+
let nbox = WBox<Thing>()
68+
nbox.wref = box.wref
69+
_blackHole(nbox)
70+
}
71+
}
72+
}
73+
74+
WeakReferenceRaceTests.test("class instance property [SR-192] (copy)") {
75+
runRaceTest(RaceTest_instancePropertyCopy.self, trials: iterations)
76+
}
77+
78+
struct RaceTest_instancePropertyLoad: WeakReferenceRaceTest {
79+
func makeRaceData() -> WeakReferenceRaceData {
80+
// Capture a weak reference via its container object
81+
// "https://bugs.swift.org/browse/SR-192"
82+
let box = WBox(Thing())
83+
return WeakReferenceRaceData {
84+
if let ref = box.wref {
85+
_blackHole(ref)
86+
}
87+
}
88+
}
89+
}
90+
91+
WeakReferenceRaceTests.test("class instance property [SR-192] (load)") {
92+
runRaceTest(RaceTest_instancePropertyLoad.self, trials: iterations)
93+
}
94+
95+
struct RaceTest_directCaptureCopy: WeakReferenceRaceTest {
96+
func makeRaceData() -> WeakReferenceRaceData {
97+
weak var wref = Thing()
98+
return WeakReferenceRaceData {
99+
let nbox = WBox<Thing>()
100+
nbox.wref = wref
101+
_blackHole(nbox)
102+
}
103+
}
104+
}
105+
106+
WeakReferenceRaceTests.test("direct capture (copy)") {
107+
runRaceTest(RaceTest_directCaptureCopy.self, trials: iterations)
108+
}
109+
110+
struct RaceTest_directCaptureLoad: WeakReferenceRaceTest {
111+
func makeRaceData() -> WeakReferenceRaceData {
112+
weak var wref = Thing()
113+
return WeakReferenceRaceData {
114+
let nbox = WBox<Thing>()
115+
nbox.wref = wref
116+
_blackHole(nbox)
117+
}
118+
}
119+
}
120+
121+
WeakReferenceRaceTests.test("direct capture (load)") {
122+
runRaceTest(RaceTest_directCaptureLoad.self, trials: iterations)
123+
}
124+
125+
runAllTests()

0 commit comments

Comments
 (0)