EscapeUtils: consider that a pointer argument can escape a function call

Unlike addresses of indirect arguments, a pointer argument (e.g. `UnsafePointer`) can escape a function call.
For example, it can be returned.

Fixes a miscompile
rdar://154124497
This commit is contained in:
Erik Eckstein
2025-07-03 12:47:34 +02:00
parent 31408fe5cb
commit 63da299622
3 changed files with 40 additions and 1 deletions

View File

@@ -640,7 +640,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
}
// Indirect arguments cannot escape the function, but loaded values from such can.
if !followLoads(at: path) {
if argOp.value.type.isAddress && !followLoads(at: path) {
if let beginApply = apply as? BeginApplyInst {
// begin_apply can yield an address value.
if !indirectResultEscapes(of: beginApply, path: path) {

View File

@@ -984,3 +984,21 @@ bb0(%0 : $Int):
return %9 : $()
}
// CHECK-LABEL: Address escape information for escaping_pointer_through_function:
// CHECK: value: %1 = alloc_stack $Int
// CHECK-NEXT: ==> %4 = apply undef(%3) : $@convention(thin) (Builtin.RawPointer) -> UnsafeMutableRawBufferPointer
// CHECK-NEXT: ==> %5 = apply undef(%4) : $@convention(thin) (UnsafeMutableRawBufferPointer) -> ()
// CHECK-NEXT: End function escaping_pointer_through_function
sil [ossa] @escaping_pointer_through_function : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%1 = alloc_stack $Int
fix_lifetime %1
%3 = address_to_pointer %1 to $Builtin.RawPointer
%4 = apply undef(%3) : $@convention(thin) (Builtin.RawPointer) -> UnsafeMutableRawBufferPointer
%5 = apply undef(%4) : $@convention(thin) (UnsafeMutableRawBufferPointer) -> ()
dealloc_stack %1
%7 = tuple ()
return %7
}

View File

@@ -1776,3 +1776,24 @@ bb0(%0 : $*Builtin.FixedArray<10, Int>, %1 : $Int, %2 : $Int):
return %6
}
sil @forwardPtr : $@convention(thin) (Builtin.RawPointer) -> UnsafeMutableRawBufferPointer {
[global: read]
}
// CHECK-LABEL: sil [ossa] @escaping_pointer_through_function :
// CHECK: [[LD:%.*]] = load [trivial] %1
// CHECK: return [[LD]]
// CHECK-LABEL: } // end sil function 'escaping_pointer_through_function'
sil [ossa] @escaping_pointer_through_function : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
%1 = alloc_stack $Int
store %0 to [trivial] %1
%3 = address_to_pointer %1 to $Builtin.RawPointer
%4 = function_ref @forwardPtr : $@convention(thin) (Builtin.RawPointer) -> UnsafeMutableRawBufferPointer
%5 = apply %4(%3) : $@convention(thin) (Builtin.RawPointer) -> UnsafeMutableRawBufferPointer
%6 = apply undef(%5) : $@convention(thin) (UnsafeMutableRawBufferPointer) -> ()
%7 = load [trivial] %1
dealloc_stack %1
return %7
}