diff options
author | Michael Gottesman <mgottesman@apple.com> | 2013-04-18 05:39:45 +0000 |
---|---|---|
committer | Michael Gottesman <mgottesman@apple.com> | 2013-04-18 05:39:45 +0000 |
commit | 0556900b260eed881a2f47a2b5267ae3a7cc7ae0 (patch) | |
tree | 52ee4c83f19137ad18305a7edf6c58e6cfb8152d /test/Transforms/ObjCARC | |
parent | 8a709208ede8eb387a2911c5ba11e5acf8cc69ae (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.ll | 36 |
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 !{} |