[ObjCArc] Do not dereference an invalidated iterator.
authorAkira Hatanaka <ahatanaka@apple.com>
Wed, 5 Apr 2017 03:44:09 +0000 (03:44 +0000)
committerAkira Hatanaka <ahatanaka@apple.com>
Wed, 5 Apr 2017 03:44:09 +0000 (03:44 +0000)
Fix a bug in ARC contract pass where an iterator that pointed to a
deleted instruction was dereferenced.

It appears that tryToContractReleaseIntoStoreStrong was incorrectly
assuming that a call to objc_retain would not immediately follow a call
to objc_release.

rdar://problem/25276306

llvm-svn: 299507

llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp
llvm/test/Transforms/ObjCARC/contract-storestrong.ll

index 23c1f59..a86eaae 100644 (file)
@@ -394,6 +394,7 @@ void ObjCARCContract::tryToContractReleaseIntoStoreStrong(Instruction *Release,
 
   DEBUG(llvm::dbgs() << "        New Store Strong: " << *StoreStrong << "\n");
 
+  if (&*Iter == Retain) ++Iter;
   if (&*Iter == Store) ++Iter;
   Store->eraseFromParent();
   Release->eraseFromParent();
index 2b83bdb..a02f7b7 100644 (file)
@@ -243,6 +243,19 @@ entry:
   ret void
 }
 
+; This used to crash.
+; CHECK-LABEL: define i8* @test13(
+; CHECK: tail call void @objc_storeStrong(i8** %{{.*}}, i8* %[[NEW:.*]])
+; CHECK-NEXT: ret i8* %[[NEW]]
+
+define i8* @test13(i8* %a0, i8* %a1, i8** %addr, i8* %new) {
+  %old = load i8*, i8** %addr, align 8
+  call void @objc_release(i8* %old)
+  %retained = call i8* @objc_retain(i8* %new)
+  store i8* %retained, i8** %addr, align 8
+  ret i8* %retained
+}
+
 !0 = !{}
 
 ; CHECK: attributes [[NUW]] = { nounwind }