blob: 6656bb3f39e3c517c30cfbc4afff39f0d1989fed [file] [log] [blame]
// RUN: %target-sil-opt -module-name Swift -sil-ownership-verifier-enable-testing -enable-sil-verify-all=0 %s -o /dev/null 2>&1 | %FileCheck %s
// REQUIRES: asserts
// This is a test that verifies ownership behavior around arguments that should
// be flagged as failures.
sil_stage canonical
import Builtin
// CHECK-LABEL: Function: 'no_end_borrow_error'
// CHECK: Non trivial values, non address values, and non guaranteed function args must have at least one lifetime ending use?!
// CHECK: Value: %2 = argument of bb1 : $Builtin.NativeObject
//
// TODO: Better error message here.
sil [ossa] @no_end_borrow_error : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
bb0(%0 : @guaranteed $Builtin.NativeObject):
br bb1(%0 : $Builtin.NativeObject)
bb1(%1 : @guaranteed $Builtin.NativeObject):
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: Function: 'leak_along_path'
// CHECK-NEXT: Error! Found a leak due to a consuming post-dominance failure!
// CHECK-NEXT: Value: %2 = argument of bb1 : $Builtin.NativeObject
// CHECK-NEXT: Post Dominating Failure Blocks:
// CHECK-NEXT: bb3
sil [ossa] @leak_along_path : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
bb0(%0 : @guaranteed $Builtin.NativeObject):
br bb1(%0 : $Builtin.NativeObject)
bb1(%1 : @guaranteed $Builtin.NativeObject):
cond_br undef, bb2, bb3
bb2:
end_borrow %1 : $Builtin.NativeObject
br bb3
bb3:
%9999 = tuple()
return %9999 : $()
}
// Make sure that we only flag the subargument leak and not the parent argument.
//
// CHECK-LABEL: Function: 'leak_along_subarg_path'
// CHECK-NEXT: Error! Found a leak due to a consuming post-dominance failure!
// CHECK-NEXT: Value: %5 = argument of bb3 : $Builtin.NativeObject
// CHECK-NEXT: Post Dominating Failure Blocks:
// CHECK-NEXT: bb5
sil [ossa] @leak_along_subarg_path : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
bb0(%0 : @guaranteed $Builtin.NativeObject):
br bb1(%0 : $Builtin.NativeObject)
bb1(%1 : @guaranteed $Builtin.NativeObject):
cond_br undef, bb2, bb5
bb2:
br bb3(%1 : $Builtin.NativeObject)
bb3(%2 : @guaranteed $Builtin.NativeObject):
cond_br undef, bb4, bb5
bb4:
end_borrow %2 : $Builtin.NativeObject
br bb5
bb5:
end_borrow %1 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-NOT: Function: 'good_order'
sil [ossa] @good_order : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = begin_borrow %0 : $Builtin.NativeObject
cond_br undef, bb1, bb5
bb1:
br bb2(%1 : $Builtin.NativeObject)
bb2(%2 : @guaranteed $Builtin.NativeObject):
end_borrow %2 : $Builtin.NativeObject
end_borrow %1 : $Builtin.NativeObject
cond_br undef, bb3, bb4
bb3:
br bb4
bb4:
destroy_value %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
bb5:
end_borrow %1 : $Builtin.NativeObject
br bb4
}
// Make sure that we only flag the end_borrow "use after free" in bb2.
//
// CHECK-LABEL: Function: 'bad_order'
// CHECK-NEXT: Found use after free?!
// CHECK-NEXT: Value: %1 = begin_borrow %0 : $Builtin.NativeObject
// CHECK-NEXT: Consuming User: end_borrow %1 : $Builtin.NativeObject
// CHECK-NEXT: Non Consuming User: end_borrow %4 : $Builtin.NativeObject // id: %6
// CHECK-NEXT: Block: bb2
// CHECK-LABEL: Function: 'bad_order'
// CHECK-NEXT: Found use after free due to unvisited non lifetime ending uses?!
// CHECK-NEXT: Value: %1 = begin_borrow %0 : $Builtin.NativeObject
// CHECK-NEXT: Remaining Users:
// CHECK-NEXT: User: end_borrow %4 : $Builtin.NativeObject
// CHECK-NEXT: Block: bb2
// CHECK-NOT: Block: bb1
sil [ossa] @bad_order : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = begin_borrow %0 : $Builtin.NativeObject
cond_br undef, bb1, bb5
bb1:
br bb2(%1 : $Builtin.NativeObject)
bb2(%2 : @guaranteed $Builtin.NativeObject):
end_borrow %1 : $Builtin.NativeObject
end_borrow %2 : $Builtin.NativeObject
cond_br undef, bb3, bb4
bb3:
br bb4
bb4:
destroy_value %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
bb5:
end_borrow %1 : $Builtin.NativeObject
br bb4
}
// CHECK-LABEL: Function: 'bad_order_add_a_level'
// CHECK-NEXT: Found use after free?!
// CHECK-NEXT: Value: %1 = begin_borrow %0 : $Builtin.NativeObject
// CHECK-NEXT: Consuming User: end_borrow %1 : $Builtin.NativeObject
// CHECK-NEXT: Non Consuming User: end_borrow %4 : $Builtin.NativeObject
// CHECK-NEXT: Block: bb2
//
// CHECK-LABEL: Function: 'bad_order_add_a_level'
// CHECK-NEXT: Found over consume?!
// CHECK-NEXT: Value: %1 = begin_borrow %0 : $Builtin.NativeObject
// CHECK-NEXT: User: end_borrow %1 : $Builtin.NativeObject
// CHECK-NEXT: Block: bb2
//
// CHECK-LABEL: Function: 'bad_order_add_a_level'
// CHECK-NEXT: Error! Found a leak due to a consuming post-dominance failure!
// CHECK-NEXT: Value: %1 = begin_borrow %0
// CHECK-NEXT: Post Dominating Failure Blocks:
// CHECK-NEXT: bb3
//
// This error is a "use after free" error b/c we are accessing the argument
// /after/ we end the parent borrow. We /could/ improve the error message here.
//
// CHECK-LABEL: Function: 'bad_order_add_a_level'
// CHECK-NEXT: Found use after free due to unvisited non lifetime ending uses?!
// CHECK-NEXT: Value: %1 = begin_borrow
// CHECK-NEXT: Remaining Users:
// CHECK-NEXT: User: end_borrow %4
// CHECK-NEXT: Block: bb2
//
// CHECK-LABEL: Function: 'bad_order_add_a_level'
// CHECK-NEXT: Found over consume?!
// CHECK-NEXT: Value: %4 = argument of bb2 : $Builtin.NativeObject
// CHECK-NEXT: User: end_borrow %4 : $Builtin.NativeObject
// CHECK-NEXT: Block: bb2
//
// CHECK-LABEL: Function: 'bad_order_add_a_level'
// CHECK-NEXT: Error! Found a leak due to a consuming post-dominance failure!
//
// CHECK-LABEL: Function: 'bad_order_add_a_level'
// CHECK-NEXT: Found use after free due to unvisited non lifetime ending uses?!
//
// CHECK-LABEL: Function: 'bad_order_add_a_level'
// CHECK-NEXT: Non trivial values, non address values, and non guaranteed function args must have at least one lifetime ending use?!
// CHECK-NEXT: Value: %9 = argument of bb4 : $Builtin.NativeObject
// NOTE: We use the expected numbered value in the output to make it easier to
// match the filecheck patterns with the input.
sil [ossa] @bad_order_add_a_level : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = begin_borrow %0 : $Builtin.NativeObject
cond_br undef, bb1, bb7
bb1:
br bb2(%1 : $Builtin.NativeObject)
bb2(%4 : @guaranteed $Builtin.NativeObject):
end_borrow %1 : $Builtin.NativeObject
end_borrow %4 : $Builtin.NativeObject
cond_br undef, bb3, bb5
bb3:
br bb4(%4 : $Builtin.NativeObject)
bb4(%9 : @guaranteed $Builtin.NativeObject):
br bb6
bb5:
end_borrow %4 : $Builtin.NativeObject
end_borrow %1 : $Builtin.NativeObject
br bb6
bb6:
destroy_value %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
bb7:
end_borrow %1 : $Builtin.NativeObject
br bb6
}
// Check that we only add an argument to the use set of its parent argument.
// This ensures that when checking we do not waste a bunch of compile time by
// propagating up end_borrows through many arguments. Also make sure that we do
// properly visit terminators so that we do not erroneously flag them as
// improper uses.
//
//
// CHECK-LABEL: Function: 'bad_order_add_a_level_2'
// CHECK-NEXT: Found use after free?!
// CHECK-NEXT: Value: %1 = begin_borrow %0 : $Builtin.NativeObject
// CHECK-NEXT: Consuming User: end_borrow %1 : $Builtin.NativeObject
// CHECK-NEXT: Non Consuming User: end_borrow %4 : $Builtin.NativeObject
// CHECK-NEXT: Block: bb2
//
// CHECK-LABEL: Function: 'bad_order_add_a_level_2'
// CHECK-NEXT: Found use after free?!
// CHECK-NEXT: Value: %1 = begin_borrow %0 : $Builtin.NativeObject
// CHECK-NEXT: Consuming User: end_borrow %1 : $Builtin.NativeObject
// CHECK-NEXT: Non Consuming User: end_borrow %4 : $Builtin.NativeObject
// CHECK-NEXT: Block: bb4
//
// CHECK-LABEL: Function: 'bad_order_add_a_level_2'
// CHECK-NEXT: Found use after free?!
// CHECK-NEXT: Value: %1 = begin_borrow %0 : $Builtin.NativeObject
// CHECK-NEXT: Consuming User: end_borrow %1 : $Builtin.NativeObject
// CHECK-NEXT: Non Consuming User: end_borrow %4 : $Builtin.NativeObject
// CHECK-NEXT: Block: bb5
//
// CHECK-LABEL: Function: 'bad_order_add_a_level_2'
// CHECK-NEXT: Found over consume?!
// CHECK-NEXT: Value: %1 = begin_borrow %0 : $Builtin.NativeObject
// CHECK-NEXT: User: end_borrow %1 : $Builtin.NativeObject
// CHECK-NEXT: Block: bb2
//
// This comes from the dataflow, but we already actually identified this error.
//
// CHECK-LABEL: Function: 'bad_order_add_a_level_2'
// CHECK-NEXT: Found over consume?!
//
// These are handled via other checks.
// CHECK-LABEL: Function: 'bad_order_add_a_level_2'
// CHECK-NEXT: Found use after free due to unvisited non lifetime ending uses?!
// CHECK-LABEL: Function: 'bad_order_add_a_level_2'
// CHECK-NEXT: Found use after free due to unvisited non lifetime ending uses?!
// CHECK-LABEL: Function: 'bad_order_add_a_level_2'
// CHECK-NEXT: Found use after free due to unvisited non lifetime ending uses?!
//
// CHECK-LABEL: Function: 'bad_order_add_a_level_2'
// CHECK-NEXT: Found use after free?!
// CHECK-NEXT: Value: %4 = argument of bb2 : $Builtin.NativeObject
// CHECK-NEXT: Consuming User: end_borrow %4 : $Builtin.NativeObject
// CHECK-NEXT: Non Consuming User: end_borrow %9 : $Builtin.NativeObject
// CHECK-NEXT: Block: bb4
// CHECK-LABEL: Function: 'bad_order_add_a_level_2'
// CHECK-NEXT: Found over consume?!
// CHECK-NEXT: Value: %4 = argument of bb2 : $Builtin.NativeObject
// CHECK-NEXT: User: end_borrow %4 : $Builtin.NativeObject
// CHECK-NEXT: Block: bb2
sil [ossa] @bad_order_add_a_level_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = begin_borrow %0 : $Builtin.NativeObject
cond_br undef, bb1, bb7
bb1:
br bb2(%1 : $Builtin.NativeObject)
bb2(%4 : @guaranteed $Builtin.NativeObject):
end_borrow %1 : $Builtin.NativeObject
end_borrow %4 : $Builtin.NativeObject
cond_br undef, bb3, bb5
bb3:
br bb4(%4 : $Builtin.NativeObject)
bb4(%9 : @guaranteed $Builtin.NativeObject):
end_borrow %1 : $Builtin.NativeObject
end_borrow %4 : $Builtin.NativeObject
end_borrow %9 : $Builtin.NativeObject
br bb6
bb5:
end_borrow %1 : $Builtin.NativeObject
end_borrow %4 : $Builtin.NativeObject
br bb6
bb6:
destroy_value %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
bb7:
end_borrow %1 : $Builtin.NativeObject
br bb6
}
// CHECK-LABEL: Function: 'owned_argument_overuse_br1'
// CHECK-NEXT: Found over consume?!
// CHECK-NEXT: Value: %0 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: User: br bb1(%0 : $Builtin.NativeObject)
// CHECK-NEXT: Block: bb0
// CHECK-LABEL: Function: 'owned_argument_overuse_br1'
// CHECK-NEXT: Error! Found a leaked owned value that was never consumed.
// CHECK-NEXT: Value: %3 = argument of bb1 : $Builtin.NativeObject
// CHECK-NOT: Block
// CHECK-NOT: Function: 'owned_argument_overuse_br1'
sil [ossa] @owned_argument_overuse_br1 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
destroy_value %0 : $Builtin.NativeObject
br bb1(%0 : $Builtin.NativeObject)
bb1(%1 : @owned $Builtin.NativeObject):
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: Function: 'owned_argument_overuse_br2'
// CHECK-NEXT: Found over consume?!
// CHECK-NEXT: Value: %0 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: User: br bb1(%0 : $Builtin.NativeObject)
// CHECK-NEXT: Block: bb0
// CHECK-NOT: Block
// CHECK-NOT: Function: 'owned_argument_overuse_br2'
sil [ossa] @owned_argument_overuse_br2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
destroy_value %0 : $Builtin.NativeObject
br bb1(%0 : $Builtin.NativeObject)
bb1(%1 : @owned $Builtin.NativeObject):
destroy_value %1 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: Function: 'owned_argument_overuse_condbr1'
// CHECK-NEXT: Found over consume?!
// CHECK-NEXT: Value: %0 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: User: cond_br undef, bb1(%0 : $Builtin.NativeObject), bb2
// CHECK-NEXT: Block: bb0
//
// CHECK-LABEL: Function: 'owned_argument_overuse_condbr1'
// CHECK-NEXT: Error! Found a leak due to a consuming post-dominance failure!
// CHECK-NEXT: Value: %0 = argument of bb0
// CHECK-NEXT: Post Dominating Failure Blocks:
// CHECK-NEXT: bb2
//
// CHECK-LABEL: Function: 'owned_argument_overuse_condbr1'
// CHECK-NEXT: Error! Found a leaked owned value that was never consumed.
// CHECK-NEXT: Value: %3 = argument of bb1 : $Builtin.NativeObject
// CHECK-NOT: Function: 'owned_argument_overuse_condbr1'
sil [ossa] @owned_argument_overuse_condbr1 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
destroy_value %0 : $Builtin.NativeObject
cond_br undef, bb1(%0 : $Builtin.NativeObject), bb2
bb1(%1 : @owned $Builtin.NativeObject):
br bb2
bb2:
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: Function: 'owned_argument_overuse_condbr2'
// CHECK-NEXT: Found over consume?!
// CHECK-NEXT: Value: %0 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: User: cond_br undef, bb1(%0 : $Builtin.NativeObject), bb2
// CHECK-NEXT: Block: bb0
sil [ossa] @owned_argument_overuse_condbr2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
destroy_value %0 : $Builtin.NativeObject
cond_br undef, bb1(%0 : $Builtin.NativeObject), bb2
bb1(%1 : @owned $Builtin.NativeObject):
destroy_value %1 : $Builtin.NativeObject
br bb2
bb2:
%9999 = tuple()
return %9999 : $()
}