mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
The previous implementation made extremely subtle and specific assumptions about how the API is used which doesn't apply everywhere. It was trying very hard to avoid regressing performance relative to an even older implementation that didn't even try to consider deinitializer side effects. The aggressive logic was based on the idea that a release must have a corresponding retain somewhere in the same function and we don't care if the last release happens early if there are no more aliasing uses. All the unit tests I wrote previously were based on release hoisting, which happens to work given the way the API is used. But this logic is incorrect for retain sinking. In that case sinking past an "unrelated" release could cause the object to be freed early. See test/SILOptimizer/arc_crash.swift. With SemanticARC and other SIL improvements being made, I'm afraid bugs like this will begin to surface. To fix it, just remove the subtle logic to leave behind a simple and sound EscapeAnalysis API. To do better, we will need to rewrite the AliasAnalysis logic for release side effects, which is currently a tangled web. In the meantime, SemanticARC can handle many cases without EscapeAnalysis. Fixes rdar://74469299 (ARC miscompile: EscapeAnalysis::mayReleaseContent; potential use-after-free) While fixing this, add support for address-type queries too: Fixes rdar://74360041 (Assertion failed: (!releasedReference->getType().isAddress() && "an address is never a reference"), function mayReleaseContent
51 lines
1.5 KiB
Swift
51 lines
1.5 KiB
Swift
// RUN: %target-swift-frontend -O %s -parse-as-library -emit-sil -enforce-exclusivity=none -Xllvm -sil-disable-pass=function-signature-opts | %FileCheck %s
|
|
|
|
// Test ARC optimizations on source level tests that have been
|
|
// miscompiled and crash (e.g. because of use-after-free).
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// rdar://74469299 (ARC miscompile: EscapeAnalysis::mayReleaseContent;
|
|
// potential use-after-free)
|
|
// -----------------------------------------------------------------------------
|
|
|
|
public class Base {
|
|
var i = 3
|
|
init() {}
|
|
}
|
|
public class Node : Base {
|
|
var node: Base
|
|
|
|
init(node: Base) { self.node = node }
|
|
}
|
|
struct Queue {
|
|
var node: Node
|
|
}
|
|
|
|
@inline(never)
|
|
func useQueue(q: __owned Queue) {}
|
|
|
|
@inline(never)
|
|
func useNode(n: Base) -> Int {
|
|
return n.i
|
|
}
|
|
|
|
// CHECK-LABEL: sil [noinline] @$s9arc_crash14testMayReleaseAA4BaseCyF : $@convention(thin) () -> @owned Base {
|
|
// CHECK: [[BASE:%.*]] = alloc_ref $Base
|
|
// CHECK: strong_retain [[BASE]] : $Base
|
|
// CHECK: apply %{{.*}} : $@convention(thin) (@owned Queue) -> ()
|
|
// CHECK-LABEL: } // end sil function '$s9arc_crash14testMayReleaseAA4BaseCyF'
|
|
@inline(never)
|
|
public func testMayRelease() -> Base {
|
|
let n2 = Base()
|
|
let n1 = Node(node: n2)
|
|
let q = Queue(node: n1)
|
|
// n2 must not be release before useQueue.
|
|
useQueue(q: q)
|
|
return n2
|
|
}
|
|
|
|
// This crashes when testMayRelease releases the object too early.
|
|
// print("Object:")
|
|
// print(testMayRelease())
|
|
// -----------------------------------------------------------------------------
|