Skip to content

Commit 69393d5

Browse files
committed
[sil-ownership] Allow for checked_cast_br to take a guaranteed parameter.
rdar://31880847
1 parent 1db06d1 commit 69393d5

File tree

3 files changed

+221
-14
lines changed

3 files changed

+221
-14
lines changed

lib/SIL/SILOwnershipVerifier.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ static bool isOwnershipForwardingValueKind(ValueKind K) {
208208
case ValueKind::MarkUninitializedInst:
209209
case ValueKind::SelectEnumInst:
210210
case ValueKind::SwitchEnumInst:
211+
case ValueKind::CheckedCastBranchInst:
211212
return true;
212213
default:
213214
return false;
@@ -337,6 +338,12 @@ class OwnershipCompatibilityUseChecker
337338
OwnershipUseCheckerResult visitForwardingInst(SILInstruction *I) {
338339
return visitForwardingInst(I, I->getAllOperands());
339340
}
341+
342+
/// Visit a terminator instance that performs a transform like
343+
/// operation. E.x.: switch_enum, checked_cast_br. This does not include br or
344+
/// cond_br.
345+
OwnershipUseCheckerResult visitTransformingTerminatorInst(TermInst *TI);
346+
340347
OwnershipUseCheckerResult
341348
visitApplyArgument(ValueOwnershipKind RequiredConvention, bool ShouldCheck);
342349
OwnershipUseCheckerResult
@@ -520,7 +527,6 @@ CONSTANT_OWNERSHIP_INST(Trivial, false, DeallocValueBuffer)
520527
return {compatibleWithOwnership(ValueOwnershipKind::OWNERSHIP), \
521528
SHOULD_CHECK_FOR_DATAFLOW_VIOLATIONS}; \
522529
}
523-
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, CheckedCastBranch)
524530
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, CheckedCastValueBranch)
525531
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, InitExistentialOpaque)
526532
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, DeinitExistentialOpaque)
@@ -745,6 +751,18 @@ OwnershipCompatibilityUseChecker::visitCondBranchInst(CondBranchInst *CBI) {
745751

746752
OwnershipUseCheckerResult
747753
OwnershipCompatibilityUseChecker::visitSwitchEnumInst(SwitchEnumInst *SEI) {
754+
return visitTransformingTerminatorInst(SEI);
755+
}
756+
757+
OwnershipUseCheckerResult
758+
OwnershipCompatibilityUseChecker::visitCheckedCastBranchInst(
759+
CheckedCastBranchInst *SEI) {
760+
return visitTransformingTerminatorInst(SEI);
761+
}
762+
763+
OwnershipUseCheckerResult
764+
OwnershipCompatibilityUseChecker::visitTransformingTerminatorInst(
765+
TermInst *TI) {
748766
// If our operand was trivial, return early.
749767
if (compatibleWithOwnership(ValueOwnershipKind::Trivial))
750768
return {true, false};
@@ -753,11 +771,9 @@ OwnershipCompatibilityUseChecker::visitSwitchEnumInst(SwitchEnumInst *SEI) {
753771
// they have a payload, the payload's convention matches our
754772
// convention.
755773
//
756-
// *NOTE* since we are dealing with enums, we ignore trivial and no payload
757-
// enums.
758774
// *NOTE* we assume that all of our types line up and are checked by the
759775
// normal verifier.
760-
for (auto *Succ : SEI->getParent()->getSuccessorBlocks()) {
776+
for (auto *Succ : TI->getParent()->getSuccessorBlocks()) {
761777
// This must be a no-payload case... continue.
762778
if (Succ->args_size() == 0)
763779
continue;
@@ -773,10 +789,9 @@ OwnershipCompatibilityUseChecker::visitSwitchEnumInst(SwitchEnumInst *SEI) {
773789
handleError([&]() {
774790
llvm::errs()
775791
<< "Function: '" << Succ->getParent()->getName() << "'\n"
776-
<< "Error! Argument ownership kind does not match switch_enum!\n"
777-
<< "SwitchEnum: " << *SEI << "Argument: " << *Succ->getArgument(0)
778-
<< "Expected convention: " << SEI->getOperand().getOwnershipKind()
779-
<< ".\n"
792+
<< "Error! Argument ownership kind does not match terminator!\n"
793+
<< "Terminator: " << *TI << "Argument: " << *Succ->getArgument(0)
794+
<< "Expected convention: " << getOwnershipKind() << ".\n"
780795
<< "Actual convention: " << OwnershipKind << '\n'
781796
<< '\n';
782797
});

test/SIL/ownership-verifier/over_consume.sil

Lines changed: 185 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ case some(T)
2222
case none
2323
}
2424

25+
class SuperKlass {}
26+
2527
///////////
2628
// Tests //
2729
///////////
@@ -174,8 +176,8 @@ bb0(%0 : @owned $Optional<Builtin.NativeObject>):
174176
}
175177

176178
// CHECK-LABEL: Function: 'switch_enum_mismatching_argument_guaranteed_to_owned'
177-
// CHECK: Error! Argument ownership kind does not match switch_enum!
178-
// CHECK: SwitchEnum: switch_enum %0 : $Optional<Builtin.NativeObject>, case #Optional.some!enumelt.1: bb1, case #Optional.none!enumelt: bb2
179+
// CHECK: Error! Argument ownership kind does not match terminator!
180+
// CHECK: Terminator: switch_enum %0 : $Optional<Builtin.NativeObject>, case #Optional.some!enumelt.1: bb1, case #Optional.none!enumelt: bb2
179181
// CHECK: Argument: %2 = argument of bb1 : $Builtin.NativeObject
180182
// CHECK: Expected convention: guaranteed.
181183
// CHECK: Actual convention: owned
@@ -196,8 +198,8 @@ bb3:
196198
}
197199

198200
// CHECK-LABEL: Function: 'switch_enum_mismatching_argument_owned_to_guaranteed'
199-
// CHECK: Error! Argument ownership kind does not match switch_enum!
200-
// CHECK: SwitchEnum: switch_enum %0 : $Optional<Builtin.NativeObject>, case #Optional.some!enumelt.1: bb1, case #Optional.none!enumelt: bb2
201+
// CHECK: Error! Argument ownership kind does not match terminator!
202+
// CHECK: Terminator: switch_enum %0 : $Optional<Builtin.NativeObject>, case #Optional.some!enumelt.1: bb1, case #Optional.none!enumelt: bb2
201203
// CHECK: Argument: %2 = argument of bb1 : $Builtin.NativeObject
202204
// CHECK: Expected convention: owned.
203205
// CHECK: Actual convention: guaranteed
@@ -235,6 +237,7 @@ bb1(%2 : @guaranteed $Builtin.NativeObject):
235237
br bb3
236238

237239
bb2:
240+
end_borrow %1 from %0 : $Optional<Builtin.NativeObject>, $Optional<Builtin.NativeObject>
238241
br bb3
239242

240243
bb3:
@@ -243,3 +246,181 @@ bb3:
243246
return %9999 : $()
244247
}
245248

249+
// CHECK-LABEL: Function: 'checked_cast_br_mismatching_argument_guaranteed_to_owned_1'
250+
// CHECK: Error! Argument ownership kind does not match terminator!
251+
// CHECK: Terminator: checked_cast_br %0 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
252+
// CHECK: Argument: %2 = argument of bb1 : $SuperKlass
253+
// CHECK: Expected convention: guaranteed.
254+
// CHECK: Actual convention: owned
255+
256+
// CHECK-LABEL: Function: 'checked_cast_br_mismatching_argument_guaranteed_to_owned_1'
257+
// CHECK: Error! Argument ownership kind does not match terminator!
258+
// CHECK: Terminator: checked_cast_br %0 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
259+
// CHECK: Argument: %5 = argument of bb2 : $Builtin.NativeObject
260+
// CHECK: Expected convention: guaranteed.
261+
// CHECK: Actual convention: owned
262+
sil @checked_cast_br_mismatching_argument_guaranteed_to_owned_1 : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
263+
bb0(%0 : @guaranteed $Builtin.NativeObject):
264+
checked_cast_br %0 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
265+
266+
bb1(%1 : @owned $SuperKlass):
267+
destroy_value %1 : $SuperKlass
268+
br bb3
269+
270+
bb2(%2 : @owned $Builtin.NativeObject):
271+
destroy_value %2 : $Builtin.NativeObject
272+
br bb3
273+
274+
bb3:
275+
%9999 = tuple()
276+
return %9999 : $()
277+
}
278+
279+
// CHECK-LABEL: Function: 'checked_cast_br_mismatching_argument_guaranteed_to_owned_2'
280+
// CHECK: Error! Argument ownership kind does not match terminator!
281+
// CHECK: Terminator: checked_cast_br %0 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
282+
// CHECK: Argument: %5 = argument of bb2 : $Builtin.NativeObject
283+
// CHECK: Expected convention: guaranteed.
284+
// CHECK: Actual convention: owned
285+
sil @checked_cast_br_mismatching_argument_guaranteed_to_owned_2 : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
286+
bb0(%0 : @guaranteed $Builtin.NativeObject):
287+
checked_cast_br %0 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
288+
289+
bb1(%1 : @guaranteed $SuperKlass):
290+
end_borrow_argument %1 : $SuperKlass
291+
br bb3
292+
293+
bb2(%2 : @owned $Builtin.NativeObject):
294+
destroy_value %2 : $Builtin.NativeObject
295+
br bb3
296+
297+
bb3:
298+
%9999 = tuple()
299+
return %9999 : $()
300+
}
301+
302+
// CHECK-LABEL: Function: 'checked_cast_br_mismatching_argument_guaranteed_to_owned_3'
303+
// CHECK: Error! Argument ownership kind does not match terminator!
304+
// CHECK: Terminator: checked_cast_br %0 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
305+
// CHECK: Argument: %2 = argument of bb1 : $SuperKlass
306+
// CHECK: Expected convention: guaranteed.
307+
// CHECK: Actual convention: owned
308+
sil @checked_cast_br_mismatching_argument_guaranteed_to_owned_3 : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
309+
bb0(%0 : @guaranteed $Builtin.NativeObject):
310+
checked_cast_br %0 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
311+
312+
bb1(%1 : @owned $SuperKlass):
313+
destroy_value %1 : $SuperKlass
314+
br bb3
315+
316+
bb2(%2 : @guaranteed $Builtin.NativeObject):
317+
end_borrow_argument %2 : $Builtin.NativeObject
318+
br bb3
319+
320+
bb3:
321+
%9999 = tuple()
322+
return %9999 : $()
323+
}
324+
325+
// CHECK-LABEL: Function: 'checked_cast_br_mismatching_argument_owned_to_guaranteed_1'
326+
// CHECK: Error! Argument ownership kind does not match terminator!
327+
// CHECK: Terminator: checked_cast_br %0 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
328+
// CHECK: Argument: %2 = argument of bb1 : $SuperKlass
329+
// CHECK: Expected convention: owned.
330+
// CHECK: Actual convention: guaranteed
331+
// CHECK-LABEL: Function: 'checked_cast_br_mismatching_argument_owned_to_guaranteed_1'
332+
// CHECK: Error! Argument ownership kind does not match terminator!
333+
// CHECK: Terminator: checked_cast_br %0 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
334+
// CHECK: Argument: %5 = argument of bb2 : $Builtin.NativeObject
335+
// CHECK: Expected convention: owned.
336+
// CHECK: Actual convention: guaranteed
337+
sil @checked_cast_br_mismatching_argument_owned_to_guaranteed_1 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
338+
bb0(%0 : @owned $Builtin.NativeObject):
339+
checked_cast_br %0 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
340+
341+
bb1(%1 : @guaranteed $SuperKlass):
342+
end_borrow_argument %1 : $SuperKlass
343+
br bb3
344+
345+
bb2(%2 : @guaranteed $Builtin.NativeObject):
346+
end_borrow_argument %2 : $Builtin.NativeObject
347+
br bb3
348+
349+
bb3:
350+
%9999 = tuple()
351+
return %9999 : $()
352+
}
353+
354+
355+
// CHECK-LABEL: Function: 'checked_cast_br_mismatching_argument_owned_to_guaranteed_2'
356+
// CHECK: Error! Argument ownership kind does not match terminator!
357+
// CHECK: Terminator: checked_cast_br %0 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
358+
// CHECK: Argument: %2 = argument of bb1 : $SuperKlass
359+
// CHECK: Expected convention: owned.
360+
// CHECK: Actual convention: guaranteed
361+
sil @checked_cast_br_mismatching_argument_owned_to_guaranteed_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
362+
bb0(%0 : @owned $Builtin.NativeObject):
363+
checked_cast_br %0 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
364+
365+
bb1(%1 : @guaranteed $SuperKlass):
366+
end_borrow_argument %1 : $SuperKlass
367+
br bb3
368+
369+
bb2(%2 : @owned $Builtin.NativeObject):
370+
destroy_value %2 : $Builtin.NativeObject
371+
br bb3
372+
373+
bb3:
374+
%9999 = tuple()
375+
return %9999 : $()
376+
}
377+
378+
// CHECK-LABEL: Function: 'checked_cast_br_mismatching_argument_owned_to_guaranteed_3'
379+
// CHECK: Error! Argument ownership kind does not match terminator!
380+
// CHECK: Terminator: checked_cast_br %0 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
381+
// CHECK: Argument: %5 = argument of bb2 : $Builtin.NativeObject
382+
// CHECK: Expected convention: owned.
383+
// CHECK: Actual convention: guaranteed
384+
sil @checked_cast_br_mismatching_argument_owned_to_guaranteed_3 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
385+
bb0(%0 : @owned $Builtin.NativeObject):
386+
checked_cast_br %0 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
387+
388+
bb1(%1 : @owned $SuperKlass):
389+
destroy_value %1 : $SuperKlass
390+
br bb3
391+
392+
bb2(%2 : @guaranteed $Builtin.NativeObject):
393+
end_borrow_argument %2 : $Builtin.NativeObject
394+
br bb3
395+
396+
bb3:
397+
%9999 = tuple()
398+
return %9999 : $()
399+
}
400+
401+
// CHECK-LABEL: Function: 'checked_cast_br_guaranteed_arg_outlives_original_value'
402+
// CHECK: Found use after free?!
403+
// CHECK: Value: %1 = begin_borrow %0 : $Builtin.NativeObject
404+
// CHECK: Consuming User: end_borrow %1 from %0 : $Builtin.NativeObject, $Builtin.NativeObject
405+
// CHECK: Non Consuming User: end_borrow_argument %7 : $Builtin.NativeObject
406+
// CHECK: Block: bb2
407+
sil @checked_cast_br_guaranteed_arg_outlives_original_value : $@convention(thin) (@owned Builtin.NativeObject) -> () {
408+
bb0(%0 : @owned $Builtin.NativeObject):
409+
%1 = begin_borrow %0 : $Builtin.NativeObject
410+
checked_cast_br %1 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
411+
412+
bb1(%2 : @guaranteed $SuperKlass):
413+
end_borrow_argument %2 : $SuperKlass
414+
end_borrow %1 from %0 : $Builtin.NativeObject, $Builtin.NativeObject
415+
br bb3
416+
417+
bb2(%3 : @guaranteed $Builtin.NativeObject):
418+
end_borrow %1 from %0 : $Builtin.NativeObject, $Builtin.NativeObject
419+
end_borrow_argument %3 : $Builtin.NativeObject
420+
br bb3
421+
422+
bb3:
423+
destroy_value %0 : $Builtin.NativeObject
424+
%9999 = tuple()
425+
return %9999 : $()
426+
}

test/SIL/ownership-verifier/use_verifier.sil

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -632,8 +632,8 @@ bb51:
632632
}
633633

634634
// We check first for objects and then for metatypes.
635-
sil @checked_cast_br_test : $@convention(thin) (@owned Builtin.NativeObject) -> () {
636-
bb0(%0 : @owned $Builtin.NativeObject):
635+
sil @checked_cast_br_test : $@convention(thin) (@owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
636+
bb0(%0 : @owned $Builtin.NativeObject, %6 : @guaranteed $Builtin.NativeObject):
637637
checked_cast_br %0 : $Builtin.NativeObject to $SuperKlass, bb1, bb2
638638

639639
bb1(%1 : @owned $SuperKlass):
@@ -655,6 +655,17 @@ bb5(%5 : @trivial $@thick SuperKlass.Type):
655655
br bb6
656656

657657
bb6:
658+
checked_cast_br %6 : $Builtin.NativeObject to $SuperKlass, bb7, bb8
659+
660+
bb7(%7 : @guaranteed $SuperKlass):
661+
end_borrow_argument %7 : $SuperKlass
662+
br bb9
663+
664+
bb8(%8 : @guaranteed $Builtin.NativeObject):
665+
end_borrow_argument %8 : $Builtin.NativeObject
666+
br bb9
667+
668+
bb9:
658669
%9999 = tuple()
659670
return %9999 : $()
660671
}

0 commit comments

Comments
 (0)