Skip to content

[Exclusivity] Fix insertion/remove in AccessSet in runtime. #9082

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

Merged
merged 1 commit into from
Apr 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion stdlib/public/runtime/Exclusivity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ struct Access {
Access **getHere() const {
return reinterpret_cast<Access**>(HereAndAction & HereMask);
}

void setHere(Access **newHere) {
HereAndAction = reinterpret_cast<uintptr_t>(newHere) | uintptr_t(getAccessAction());
}

ExclusivityFlags getAccessAction() const {
return ExclusivityFlags(HereAndAction & ActionMask);
}
Expand Down Expand Up @@ -114,10 +119,14 @@ class AccessSet {
}

access->initialize(pointer, curP, action);
*curP = access;
}

static void remove(Access *access) {
*access->getHere() = access->Next;
Access **here = access->getHere();
*here = access->Next;
if (access->Next != nullptr)
access->Next->setHere(here);
}
};

Expand Down
114 changes: 114 additions & 0 deletions test/Interpreter/enforce_exclusive_access.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: %target-build-swift %s -o %t/a.out -enforce-exclusivity=checked
//
// RUN: %target-run %t/a.out
// REQUIRES: executable_test

// Tests for traps at run time when enforcing exclusive access.

import StdlibUnittest

struct X {
var i = 7
}

/// Calling this function will begin a read access to the variable referred to
/// in the first parameter that lasts for the duration of the call. Any
/// accesses in the closure will therefore be nested inside the outer read.
func readAndPerform<T>(_ _: UnsafePointer<T>, closure: () ->()) {
closure()
}

/// Begin a modify access to the first paraemter and call the closure inside it.
func modifyAndPerform<T>(_ _: UnsafeMutablePointer<T>, closure: () ->()) {
closure()
}

var globalX = X()

var ExclusiveAccessTestSuite = TestSuite("ExclusiveAccess")

ExclusiveAccessTestSuite.test("Read") {
let l = globalX // no-trap
_blackHole(l)
}

// It is safe for a read access to overlap with a read.
ExclusiveAccessTestSuite.test("ReadInsideRead") {
readAndPerform(&globalX) {
let l = globalX // no-trap
_blackHole(l)
}
}

ExclusiveAccessTestSuite.test("ModifyInsideRead")
.skip(.custom(
{ _isFastAssertConfiguration() },
reason: "this trap is not guaranteed to happen in -Ounchecked"))
.crashOutputMatches("modify/read access conflict detected on address")
.code
{
readAndPerform(&globalX) {
expectCrashLater()
globalX = X()
}
}

ExclusiveAccessTestSuite.test("ReadInsideModify")
.skip(.custom(
{ _isFastAssertConfiguration() },
reason: "this trap is not guaranteed to happen in -Ounchecked"))
.crashOutputMatches("read/modify access conflict detected on address")
.code
{
modifyAndPerform(&globalX) {
expectCrashLater()
let l = globalX
_blackHole(l)
}
}

ExclusiveAccessTestSuite.test("ModifyInsideModify")
.skip(.custom(
{ _isFastAssertConfiguration() },
reason: "this trap is not guaranteed to happen in -Ounchecked"))
.crashOutputMatches("modify/modify access conflict detected on address")
.code
{
modifyAndPerform(&globalX) {
expectCrashLater()
globalX.i = 12
}
}

var globalOtherX = X()

// It is safe for two modifications of different variables
// to overlap.
ExclusiveAccessTestSuite.test("ModifyInsideModifyOfOther") {
modifyAndPerform(&globalOtherX) {
globalX.i = 12 // no-trap
}
}

// The access durations for these two modifications do not overlap
ExclusiveAccessTestSuite.test("ModifyFollowedByModify") {
globalX = X()
_blackHole(())

globalX = X() // no-trap
}

ExclusiveAccessTestSuite.test("ClosureCaptureModifyModify") {
var x = X()
modifyAndPerform(&x) {
// FIXME: This should be caught dynamically.
x.i = 12
}
}




runAllTests()