Skip to content

Commit e911e1f

Browse files
authored
Merge pull request #17935 from atrick/fix-keypath-exclusivity-verify
Teach exclusivity access marker verifier to handle UnsafePointer.
2 parents e5ad88d + 5373f34 commit e911e1f

File tree

3 files changed

+62
-6
lines changed

3 files changed

+62
-6
lines changed

lib/SIL/MemAccessUtils.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,16 @@ static bool isExternalGlobalAddressor(ApplyInst *AI) {
181181
return funcRef->isGlobalInit() && funcRef->isExternalDeclaration();
182182
}
183183

184+
// Return true if the given StructExtractInst extracts the RawPointer from
185+
// Unsafe[Mutable]Pointer.
186+
static bool isUnsafePointerExtraction(StructExtractInst *SEI) {
187+
assert(isa<BuiltinRawPointerType>(SEI->getType().getASTType()));
188+
auto &C = SEI->getModule().getASTContext();
189+
auto *decl = SEI->getStructDecl();
190+
return decl == C.getUnsafeMutablePointerDecl()
191+
|| decl == C.getUnsafePointerDecl();
192+
}
193+
184194
// Given an address base is a block argument, verify that it is actually a box
185195
// projected from a switch_enum. This is a valid pattern at any SIL stage
186196
// resulting in a block-type phi. In later SIL stages, the optimizer may form
@@ -231,6 +241,12 @@ AccessedStorage swift::findAccessedStorage(SILValue sourceAddr) {
231241
if (kind != AccessedStorage::Unidentified)
232242
return AccessedStorage(address, kind);
233243

244+
// If the address producer cannot immediately be classified, follow the
245+
// use-def chain of address, box, or RawPointer producers.
246+
assert(address->getType().isAddress()
247+
|| isa<SILBoxType>(address->getType().getASTType())
248+
|| isa<BuiltinRawPointerType>(address->getType().getASTType()));
249+
234250
// Handle other unidentified address sources.
235251
switch (address->getKind()) {
236252
default:
@@ -248,6 +264,14 @@ AccessedStorage swift::findAccessedStorage(SILValue sourceAddr) {
248264
// Don't currently allow any other calls to return an accessed address.
249265
return AccessedStorage();
250266

267+
case ValueKind::StructExtractInst:
268+
// Handle nested access to a KeyPath projection. The projection itself
269+
// uses a Builtin. However, the returned UnsafeMutablePointer may be
270+
// converted to an address and accessed via an inout argument.
271+
if (isUnsafePointerExtraction(cast<StructExtractInst>(address)))
272+
return AccessedStorage(address, AccessedStorage::Unidentified);
273+
return AccessedStorage();
274+
251275
// A block argument may be a box value projected out of
252276
// switch_enum. Address-type block arguments are not allowed.
253277
case ValueKind::SILPHIArgument:
@@ -276,6 +300,12 @@ AccessedStorage swift::findAccessedStorage(SILValue sourceAddr) {
276300
return AccessedStorage();
277301
}
278302

303+
// ref_tail_addr project an address from a reference.
304+
// This is a valid address producer for nested @inout argument
305+
// access, but it is never used for formal access of identified objects.
306+
case ValueKind::RefTailAddrInst:
307+
return AccessedStorage(address, AccessedStorage::Unidentified);
308+
279309
// Inductive cases:
280310
// Look through address casts to find the source address.
281311
case ValueKind::MarkUninitializedInst:
@@ -297,8 +327,8 @@ AccessedStorage swift::findAccessedStorage(SILValue sourceAddr) {
297327
continue;
298328

299329
// Access to a Builtin.RawPointer. Treat this like the inductive cases
300-
// above because some RawPointer's originate from identified locations. See
301-
// the special case for global addressors, which return RawPointer above.
330+
// above because some RawPointers originate from identified locations. See
331+
// the special case for global addressors, which return RawPointer, above.
302332
//
303333
// If the inductive search does not find a valid addressor, it will
304334
// eventually reach the default case that returns in invalid location. This
@@ -320,11 +350,10 @@ AccessedStorage swift::findAccessedStorage(SILValue sourceAddr) {
320350
address = cast<SingleValueInstruction>(address)->getOperand(0);
321351
continue;
322352

323-
// Subobject projections.
353+
// Address-to-address subobject projections.
324354
case ValueKind::StructElementAddrInst:
325355
case ValueKind::TupleElementAddrInst:
326356
case ValueKind::UncheckedTakeEnumDataAddrInst:
327-
case ValueKind::RefTailAddrInst:
328357
case ValueKind::TailAddrInst:
329358
case ValueKind::IndexAddrInst:
330359
address = cast<SingleValueInstruction>(address)->getOperand(0);

test/Interpreter/enforce_exclusive_access.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
//
44
// RUN: %target-run %t/a.out
55
// REQUIRES: executable_test
6-
// REQUIRES: rdar41660554
76

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

@@ -306,7 +305,7 @@ ExclusiveAccessTestSuite.test("SequentialKeyPathWritesDontOverlap") {
306305

307306
c[keyPath: getF] = 7
308307
c[keyPath: getF] = 8 // no-trap
309-
c[keyPath: getF] += c[keyPath: getF] + 1 // no-trap
308+
c[keyPath: getF] += c[keyPath: getF] // no-trap
310309
}
311310

312311
ExclusiveAccessTestSuite.test("KeyPathInoutKeyPathWriteClassStoredProp")

test/SILOptimizer/exclusivity_static_diagnostics.sil

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,3 +1106,31 @@ bb0(%0 : $UnsafePointer<Int32>, %1 : $*Int32):
11061106
%v = tuple ()
11071107
return %v : $()
11081108
}
1109+
1110+
// <rdar://problem/41660554> Swift CI (macOS release master, OSS): SIL verification failed: Unknown formal access pattern: storage
1111+
// Test access marker verification of a KeyPath projection with nested @inout access after inlining.
1112+
sil @takeInoutInt : $@convention(thin) (@inout Int) -> ()
1113+
1114+
// The compiler intrinsic _projectXXXKeyPath returns a tuple of
1115+
// UnsafePointer and Optional AnyObject. After inlining, the unsafe
1116+
// pointer may appear to originate from anywhere, including a phi.
1117+
// There's currently no way to tell that the UnsafePointer originated
1118+
// from a KeyPath projection. This pattern could occur with any
1119+
// addressor. In either case, the nested access is valid but
1120+
// unidentified. Addressors that require enforcement must start a
1121+
// dynamic access within the addressor itself, before returning an
1122+
// UnsafePointer.
1123+
sil @testNestedKeypathAccess : $@convention(thin) (@guaranteed (UnsafeMutablePointer<Int>, Optional<AnyObject>)) -> () {
1124+
bb0(%0 : $(UnsafeMutablePointer<Int>, Optional<AnyObject>)):
1125+
%up = tuple_extract %0 : $(UnsafeMutablePointer<Int>, Optional<AnyObject>), 0
1126+
%o = tuple_extract %0 : $(UnsafeMutablePointer<Int>, Optional<AnyObject>), 1
1127+
%p = struct_extract %up : $UnsafeMutablePointer<Int>, #UnsafeMutablePointer._rawValue
1128+
%adr = pointer_to_address %p : $Builtin.RawPointer to [strict] $*Int
1129+
%dep = mark_dependence %adr : $*Int on %o : $Optional<AnyObject>
1130+
%access = begin_access [modify] [static] %dep : $*Int
1131+
%f = function_ref @takeInoutInt : $@convention(thin) (@inout Int) -> ()
1132+
%call = apply %f(%access) : $@convention(thin) (@inout Int) -> ()
1133+
end_access %access : $*Int
1134+
%v = tuple ()
1135+
return %v : $()
1136+
}

0 commit comments

Comments
 (0)