Skip to content

Commit 97a9bfa

Browse files
authored
Merge pull request #9082 from devincoughlin/test-global-access-traps
2 parents 06c3c99 + 73aabd7 commit 97a9bfa

File tree

2 files changed

+124
-1
lines changed

2 files changed

+124
-1
lines changed

stdlib/public/runtime/Exclusivity.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ struct Access {
6969
Access **getHere() const {
7070
return reinterpret_cast<Access**>(HereAndAction & HereMask);
7171
}
72+
73+
void setHere(Access **newHere) {
74+
HereAndAction = reinterpret_cast<uintptr_t>(newHere) | uintptr_t(getAccessAction());
75+
}
76+
7277
ExclusivityFlags getAccessAction() const {
7378
return ExclusivityFlags(HereAndAction & ActionMask);
7479
}
@@ -114,10 +119,14 @@ class AccessSet {
114119
}
115120

116121
access->initialize(pointer, curP, action);
122+
*curP = access;
117123
}
118124

119125
static void remove(Access *access) {
120-
*access->getHere() = access->Next;
126+
Access **here = access->getHere();
127+
*here = access->Next;
128+
if (access->Next != nullptr)
129+
access->Next->setHere(here);
121130
}
122131
};
123132

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: %target-build-swift %s -o %t/a.out -enforce-exclusivity=checked
4+
//
5+
// RUN: %target-run %t/a.out
6+
// REQUIRES: executable_test
7+
8+
// Tests for traps at run time when enforcing exclusive access.
9+
10+
import StdlibUnittest
11+
12+
struct X {
13+
var i = 7
14+
}
15+
16+
/// Calling this function will begin a read access to the variable referred to
17+
/// in the first parameter that lasts for the duration of the call. Any
18+
/// accesses in the closure will therefore be nested inside the outer read.
19+
func readAndPerform<T>(_ _: UnsafePointer<T>, closure: () ->()) {
20+
closure()
21+
}
22+
23+
/// Begin a modify access to the first paraemter and call the closure inside it.
24+
func modifyAndPerform<T>(_ _: UnsafeMutablePointer<T>, closure: () ->()) {
25+
closure()
26+
}
27+
28+
var globalX = X()
29+
30+
var ExclusiveAccessTestSuite = TestSuite("ExclusiveAccess")
31+
32+
ExclusiveAccessTestSuite.test("Read") {
33+
let l = globalX // no-trap
34+
_blackHole(l)
35+
}
36+
37+
// It is safe for a read access to overlap with a read.
38+
ExclusiveAccessTestSuite.test("ReadInsideRead") {
39+
readAndPerform(&globalX) {
40+
let l = globalX // no-trap
41+
_blackHole(l)
42+
}
43+
}
44+
45+
ExclusiveAccessTestSuite.test("ModifyInsideRead")
46+
.skip(.custom(
47+
{ _isFastAssertConfiguration() },
48+
reason: "this trap is not guaranteed to happen in -Ounchecked"))
49+
.crashOutputMatches("modify/read access conflict detected on address")
50+
.code
51+
{
52+
readAndPerform(&globalX) {
53+
expectCrashLater()
54+
globalX = X()
55+
}
56+
}
57+
58+
ExclusiveAccessTestSuite.test("ReadInsideModify")
59+
.skip(.custom(
60+
{ _isFastAssertConfiguration() },
61+
reason: "this trap is not guaranteed to happen in -Ounchecked"))
62+
.crashOutputMatches("read/modify access conflict detected on address")
63+
.code
64+
{
65+
modifyAndPerform(&globalX) {
66+
expectCrashLater()
67+
let l = globalX
68+
_blackHole(l)
69+
}
70+
}
71+
72+
ExclusiveAccessTestSuite.test("ModifyInsideModify")
73+
.skip(.custom(
74+
{ _isFastAssertConfiguration() },
75+
reason: "this trap is not guaranteed to happen in -Ounchecked"))
76+
.crashOutputMatches("modify/modify access conflict detected on address")
77+
.code
78+
{
79+
modifyAndPerform(&globalX) {
80+
expectCrashLater()
81+
globalX.i = 12
82+
}
83+
}
84+
85+
var globalOtherX = X()
86+
87+
// It is safe for two modifications of different variables
88+
// to overlap.
89+
ExclusiveAccessTestSuite.test("ModifyInsideModifyOfOther") {
90+
modifyAndPerform(&globalOtherX) {
91+
globalX.i = 12 // no-trap
92+
}
93+
}
94+
95+
// The access durations for these two modifications do not overlap
96+
ExclusiveAccessTestSuite.test("ModifyFollowedByModify") {
97+
globalX = X()
98+
_blackHole(())
99+
100+
globalX = X() // no-trap
101+
}
102+
103+
ExclusiveAccessTestSuite.test("ClosureCaptureModifyModify") {
104+
var x = X()
105+
modifyAndPerform(&x) {
106+
// FIXME: This should be caught dynamically.
107+
x.i = 12
108+
}
109+
}
110+
111+
112+
113+
114+
runAllTests()

0 commit comments

Comments
 (0)