Skip to content

Commit 6cfa72d

Browse files
authored
Merge pull request #61651 from gottesmm/pr-727f8b30b3e32b1eb29003ac26642f5cf54b78e6
[silgen] Eliminate lifetime gap caused by AutoreleasingUnsafeMutablePointer's LValue component set.
2 parents 7a79d31 + 444c3ee commit 6cfa72d

File tree

3 files changed

+23
-4
lines changed

3 files changed

+23
-4
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5552,8 +5552,14 @@ class AutoreleasingWritebackComponent : public LogicalPathComponent {
55525552
unowned->getType().castTo<UnmanagedStorageType>().getReferentType());
55535553
auto owned = SGF.B.createUnmanagedToRef(loc, unowned, strongType);
55545554
auto ownedMV = SGF.emitManagedRetain(loc, owned);
5555-
5556-
// Reassign the +1 storage with it.
5555+
5556+
// Then create a mark dependence in between the base and the ownedMV. This
5557+
// is important to ensure that the destroy of the assign is not hoisted
5558+
// above the retain. We are doing unmanaged things here so we need to be
5559+
// extra careful.
5560+
ownedMV = SGF.B.createMarkDependence(loc, ownedMV, base);
5561+
5562+
// Then reassign the mark dependence into the +1 storage.
55575563
ownedMV.assignInto(SGF, loc, base.getUnmanagedValue());
55585564
}
55595565

test/SILGen/foreign_errors.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,17 @@ func test0() throws {
2828
// CHECK: [[RESULT:%.*]] = apply [[METHOD]]({{.*}}, [[SELF]])
2929

3030
// Writeback to the first temporary.
31+
//
32+
// NOTE: We need to a mark dependence here to ensure that the destroy
33+
// associated with the assign to ERR_TEMP0 is not hoisted above the copy_value
34+
// of T1_COPY. If we were to allow that, we could introduce a lifetime gap
35+
// causing potentially use after frees.
36+
//
3137
// CHECK: [[T0:%.*]] = load [trivial] [[ERR_TEMP1]]
3238
// CHECK: [[T1:%.*]] = unmanaged_to_ref [[T0]]
3339
// CHECK: [[T1_COPY:%.*]] = copy_value [[T1]]
34-
// CHECK: assign [[T1_COPY]] to [[ERR_TEMP0]]
40+
// CHECK: [[T1_COPY_DEP:%.*]] = mark_dependence [[T1_COPY]] : $Optional<NSError> on [[ERR_TEMP0]]
41+
// CHECK: assign [[T1_COPY_DEP]] to [[ERR_TEMP0]]
3542

3643
// Pull out the boolean value and compare it to zero.
3744
// CHECK: [[BOOL_OR_INT:%.*]] = struct_extract [[RESULT]]

test/SILGen/pointer_conversion.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,13 @@ func classInoutToPointer() {
250250
// CHECK: [[UNOWNED_OUT:%.*]] = load [trivial] [[WRITEBACK]]
251251
// CHECK: [[OWNED_OUT:%.*]] = unmanaged_to_ref [[UNOWNED_OUT]]
252252
// CHECK: [[OWNED_OUT_COPY:%.*]] = copy_value [[OWNED_OUT]]
253-
// CHECK: assign [[OWNED_OUT_COPY]] to [[WRITE2]]
253+
//
254+
// DISCUSSION: We need a mark_dependence here to ensure that the destroy of
255+
// the value in WRITE2 is not hoisted above the copy of OWNED_OUT. Otherwise,
256+
// we may have a use-after-free if ref counts are low enough.
257+
//
258+
// CHECK: [[OWNED_OUT_COPY_DEP:%.*]] = mark_dependence [[OWNED_OUT_COPY]] : $C on [[WRITE2]]
259+
// CHECK: assign [[OWNED_OUT_COPY_DEP]] to [[WRITE2]]
254260

255261
var cq: C? = C()
256262
takesPlusZeroOptionalPointer(&cq)

0 commit comments

Comments
 (0)