OSDN Git Service

[WinEH] Don't miscompile cleanups which conditionally unwind to caller
authorDavid Majnemer <david.majnemer@gmail.com>
Sat, 23 Jan 2016 23:54:33 +0000 (23:54 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Sat, 23 Jan 2016 23:54:33 +0000 (23:54 +0000)
A cleanup can have paths which unwind or end up in unreachable.
If there is an unreachable path *and* a path which unwinds to caller,
we would mistakenly inject an unwind path to a catchswitch on the
unreachable path.  This results in a verifier assertion firing because
the cleanup unwinds to two different places: to the caller and to the
catchswitch.

This occured because we used getCleanupRetUnwindDest to determine if the
cleanuppad had no cleanuprets.
This is incorrect, getCleanupRetUnwindDest returns null for cleanuprets
which unwind to caller.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@258651 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/WinEHPrepare.cpp
test/CodeGen/WinEH/wineh-cleanuppad-nounwind.ll

index c4eaef8..12733ac 100644 (file)
@@ -1072,7 +1072,8 @@ void WinEHPrepare::fixupNoReturnCleanupPads(Function &F) {
     if (!CleanupPad)
       continue;
     // Skip over any cleanups have unwind targets, they do not need this.
-    if (getCleanupRetUnwindDest(CleanupPad) != nullptr)
+    if (any_of(CleanupPad->users(),
+               [](const User *U) { return isa<CleanupReturnInst>(U); }))
       continue;
     // Walk the blocks within the cleanup which end in 'unreachable'.
     // We will replace the unreachable instruction with a cleanupret;
index 09b4d3b..ff6b70a 100644 (file)
@@ -65,6 +65,30 @@ exit:
   unreachable
 }
 
+; CHECK-LABEL: @test2(
+define void @test2(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
+entry:
+  invoke void @f()
+          to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont:
+  unreachable
+
+ehcleanup:
+  %cp = cleanuppad within none []
+  br i1 %B, label %ret, label %if.then
+
+if.then:
+  call void @exit(i32 1) [ "funclet"(token %cp) ]
+  unreachable
+
+ret:
+  cleanupret from %cp unwind to caller
+}
+
+; CHECK: call void @exit(i32 1) [ "funclet"(token %cp) ]
+; CHECK-NEXT: unreachable
+
 declare void @f()
 declare void @exit(i32) nounwind noreturn