File tree Expand file tree Collapse file tree 3 files changed +23
-4
lines changed Expand file tree Collapse file tree 3 files changed +23
-4
lines changed Original file line number Diff line number Diff line change @@ -5552,8 +5552,14 @@ class AutoreleasingWritebackComponent : public LogicalPathComponent {
5552
5552
unowned->getType ().castTo <UnmanagedStorageType>().getReferentType ());
5553
5553
auto owned = SGF.B .createUnmanagedToRef (loc, unowned, strongType);
5554
5554
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.
5557
5563
ownedMV.assignInto (SGF, loc, base.getUnmanagedValue ());
5558
5564
}
5559
5565
Original file line number Diff line number Diff line change @@ -28,10 +28,17 @@ func test0() throws {
28
28
// CHECK: [[RESULT:%.*]] = apply [[METHOD]]({{.*}}, [[SELF]])
29
29
30
30
// 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
+ //
31
37
// CHECK: [[T0:%.*]] = load [trivial] [[ERR_TEMP1]]
32
38
// CHECK: [[T1:%.*]] = unmanaged_to_ref [[T0]]
33
39
// 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]]
35
42
36
43
// Pull out the boolean value and compare it to zero.
37
44
// CHECK: [[BOOL_OR_INT:%.*]] = struct_extract [[RESULT]]
Original file line number Diff line number Diff line change @@ -250,7 +250,13 @@ func classInoutToPointer() {
250
250
// CHECK: [[UNOWNED_OUT:%.*]] = load [trivial] [[WRITEBACK]]
251
251
// CHECK: [[OWNED_OUT:%.*]] = unmanaged_to_ref [[UNOWNED_OUT]]
252
252
// 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]]
254
260
255
261
var cq : C ? = C ( )
256
262
takesPlusZeroOptionalPointer ( & cq)
You can’t perform that action at this time.
0 commit comments