Skip to content

Commit 179251d

Browse files
committed
[sil-combine] Do not perform existential type propagation on @in parameters when we have a copy of the underlying value.
Otherwise, we may get use-after-frees as in the added test. rdar://50609145
1 parent 580ca72 commit 179251d

File tree

3 files changed

+39
-10
lines changed

3 files changed

+39
-10
lines changed

lib/SILGen/SILGenPoly.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,12 +1119,7 @@ namespace {
11191119
// This code assumes that we have each element at +1. So, if we do
11201120
// not have a cleanup, we emit a load [copy]. This can occur if we
11211121
// are translating in_guaranteed parameters.
1122-
IsTake_t isTakeVal = ([&] {
1123-
if (elt.isPlusZero()) {
1124-
return IsNotTake;
1125-
}
1126-
return IsTake;
1127-
}());
1122+
IsTake_t isTakeVal = elt.isPlusZero() ? IsNotTake : IsTake;
11281123
elt = SGF.emitLoad(Loc, elt.forward(SGF),
11291124
SGF.getTypeLowering(elt.getType()), SGFContext(),
11301125
isTakeVal);

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -813,11 +813,12 @@ static bool canReplaceCopiedArg(FullApplySite Apply, SILValue Arg,
813813
if (!IEA)
814814
return false;
815815

816-
// If the witness method mutates Arg, we cannot replace Arg with
817-
// the source of a copy. Otherwise the call would modify another value than
818-
// the original argument.
816+
// If the witness method does not take the value as guaranteed, we cannot
817+
// replace Arg with the source of a copy. Otherwise the call would modify
818+
// another value than the original argument (in the case of indirect mutating)
819+
// or create a use-after-free (in the case of indirect consuming).
819820
auto origConv = Apply.getOrigCalleeConv();
820-
if (origConv.getParamInfoForSILArg(ArgIdx).isIndirectMutating())
821+
if (!origConv.getParamInfoForSILArg(ArgIdx).isIndirectInGuaranteed())
821822
return false;
822823

823824
auto *DT = DA->get(Apply.getFunction());

test/SILOptimizer/sil_combine_concrete_existential.sil

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,3 +499,36 @@ bb0(%0 : $Array<Int>):
499499
%25 = tuple ()
500500
return %25 : $()
501501
}
502+
503+
struct InGuaranteedArgTestNativeObjectWrapper {
504+
var i: Builtin.NativeObject
505+
}
506+
507+
protocol InGuaranteedArgTestProtocol {}
508+
extension InGuaranteedArgTestNativeObjectWrapper : InGuaranteedArgTestProtocol {}
509+
510+
sil @in_guaranteed_arg_test_callee : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> ()
511+
512+
// The current transformation is not smart enough to remove the
513+
// destroy_addr. Simply substituting the copy source for the apply argument
514+
// would introduce a use-after-free. = (.
515+
//
516+
// CHECK-LABEL: sil @in_guaranteed_arg_test_caller : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> () {
517+
// CHECK: apply {{%.*}}<@opened("C494A60E-71EA-11E9-B8C0-D0817AD3F8AD") InGuaranteedArgTestProtocol>
518+
// CHECK: } // end sil function 'in_guaranteed_arg_test_caller'
519+
sil @in_guaranteed_arg_test_caller : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> () {
520+
bb0(%0 : $*τ_0_0):
521+
%1 = alloc_stack $InGuaranteedArgTestProtocol
522+
%2 = init_existential_addr %1 : $*InGuaranteedArgTestProtocol, $τ_0_0
523+
copy_addr [take] %0 to [initialization] %2 : $*τ_0_0
524+
%3 = function_ref @in_guaranteed_arg_test_callee : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> ()
525+
%4 = alloc_stack $InGuaranteedArgTestProtocol
526+
copy_addr %1 to [initialization] %4 : $*InGuaranteedArgTestProtocol
527+
%5 = open_existential_addr mutable_access %4 : $*InGuaranteedArgTestProtocol to $*@opened("C494A60E-71EA-11E9-B8C0-D0817AD3F8AD") InGuaranteedArgTestProtocol
528+
apply %3<@opened("C494A60E-71EA-11E9-B8C0-D0817AD3F8AD") InGuaranteedArgTestProtocol>(%5) : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> ()
529+
dealloc_stack %4 : $*InGuaranteedArgTestProtocol
530+
destroy_addr %1 : $*InGuaranteedArgTestProtocol
531+
dealloc_stack %1 : $*InGuaranteedArgTestProtocol
532+
%9999 = tuple()
533+
return %9999 : $()
534+
}

0 commit comments

Comments
 (0)