aboutsummaryrefslogtreecommitdiff
path: root/test/Transforms/ObjCARC
diff options
context:
space:
mode:
authorMichael Gottesman <mgottesman@apple.com>2013-04-18 05:39:45 +0000
committerMichael Gottesman <mgottesman@apple.com>2013-04-18 05:39:45 +0000
commit0556900b260eed881a2f47a2b5267ae3a7cc7ae0 (patch)
tree52ee4c83f19137ad18305a7edf6c58e6cfb8152d /test/Transforms/ObjCARC
parent8a709208ede8eb387a2911c5ba11e5acf8cc69ae (diff)
[objc-arc] Do not mismatch up retains inside a for loop with releases outside said for loop in the presense of differing provenance caused by escaping blocks.
This occurs due to an alloca representing a separate ownership from the original pointer. Thus consider the following pseudo-IR: objc_retain(%a) for (...) { objc_retain(%a) %block <- %a F(%block) objc_release(%block) } objc_release(%a) From the perspective of the optimizer, the %block is a separate provenance from the original %a. Thus the optimizer pairs up the inner retain for %a and the outer release from %a, resulting in segfaults. This is fixed by noting that the signature of a mismatch of retain/releases inside the for loop is a Use/CanRelease top down with an None bottom up (since bottom up the Retain-CanRelease-Use-Release sequence is completed by the inner objc_retain, but top down due to the differing provenance from the objc_release said sequence is not completed). In said case in CheckForCFGHazards, we now clear the state of %a implying that no pairing will occur. Additionally a test case is included. rdar://12969722 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@179747 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/Transforms/ObjCARC')
-rw-r--r--test/Transforms/ObjCARC/cfg-hazards.ll36
1 files changed, 36 insertions, 0 deletions
diff --git a/test/Transforms/ObjCARC/cfg-hazards.ll b/test/Transforms/ObjCARC/cfg-hazards.ll
index 899298b596..0156d5bfb4 100644
--- a/test/Transforms/ObjCARC/cfg-hazards.ll
+++ b/test/Transforms/ObjCARC/cfg-hazards.ll
@@ -8,6 +8,7 @@ declare void @use_pointer(i8*)
declare i8* @objc_retain(i8*)
declare void @objc_release(i8*)
declare void @callee()
+declare void @block_callee(void ()*)
; CHECK: define void @test0(
; CHECK: call i8* @objc_retain(
@@ -394,6 +395,41 @@ exit:
ret void
}
+; Do not improperly pair retains in a for loop with releases outside of a for
+; loop when the proper pairing is disguised by a separate provenance represented
+; by an alloca.
+; rdar://12969722
+
+; CHECK: define void @test13(i8* %a) [[NUW]] {
+; CHECK: entry:
+; CHECK: tail call i8* @objc_retain(i8* %a) [[NUW]]
+; CHECK: loop:
+; CHECK: tail call i8* @objc_retain(i8* %a) [[NUW]]
+; CHECK: call void @block_callee
+; CHECK: call void @objc_release(i8* %reloaded_a) [[NUW]]
+; CHECK: exit:
+; CHECK: call void @objc_release(i8* %a) [[NUW]]
+; CHECK: }
+define void @test13(i8* %a) nounwind {
+entry:
+ %block = alloca i8*
+ %a1 = tail call i8* @objc_retain(i8* %a) nounwind
+ br label %loop
+
+loop:
+ %a2 = tail call i8* @objc_retain(i8* %a) nounwind
+ store i8* %a, i8** %block, align 8
+ %casted_block = bitcast i8** %block to void ()*
+ call void @block_callee(void ()* %casted_block)
+ %reloaded_a = load i8** %block, align 8
+ call void @objc_release(i8* %reloaded_a) nounwind, !clang.imprecise_release !0
+ br i1 undef, label %loop, label %exit
+
+exit:
+ call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
+ ret void
+}
+
; CHECK: attributes [[NUW]] = { nounwind }
!0 = metadata !{}