summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Labath <labath@google.com>2013-09-06 08:12:48 +0000
committerPavel Labath <labath@google.com>2013-09-06 08:12:48 +0000
commit921e7650d42ba46a706f2eb2516cddf6ea5a5b81 (patch)
tree9a6fdb54767dc4d54c8fbf0081815d25f20183ed
parent562ecd4444b94fbcf9c3e860991228b1fa85e273 (diff)
downloadbcm5719-llvm-921e7650d42ba46a706f2eb2516cddf6ea5a5b81.tar.gz
bcm5719-llvm-921e7650d42ba46a706f2eb2516cddf6ea5a5b81.zip
Avoid double edges when constructing CFGs
Summary: If a noreturn destructor is executed while returning a value from a function, the resulting CFG has had two edges to the exit block. This crashed the analyzer, because it expects that blocks with no terminators have only one outgoing edge. I added code to avoid creating the second edge in this case. PS: The crashes did not manifest themselves always, as usually the NoReturnFunctionChecker would stop program evaluation before the analyzer hit the assertion, but in the case of lifetime extended temporaries, the checker failed to do that (which is a separate bug in itself). Reviewers: jordan_rose CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D1513 llvm-svn: 190125
-rw-r--r--clang/lib/Analysis/CFG.cpp7
-rw-r--r--clang/test/Analysis/cfg.cpp37
2 files changed, 42 insertions, 2 deletions
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 5e03f4377d3..191c324b3c6 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -1899,9 +1899,12 @@ CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) {
// Create the new block.
Block = createBlock(false);
- // The Exit block is the only successor.
addAutomaticObjDtors(ScopePos, LocalScope::const_iterator(), R);
- addSuccessor(Block, &cfg->getExit());
+
+ // If the one of the destructors does not return, we already have the Exit
+ // block as a successor.
+ if (!Block->hasNoReturnElement())
+ addSuccessor(Block, &cfg->getExit());
// Add the return statement to the block. This may create new blocks if R
// contains control-flow (short-circuit operations).
diff --git a/clang/test/Analysis/cfg.cpp b/clang/test/Analysis/cfg.cpp
index 243e1aed99c..660d1f26469 100644
--- a/clang/test/Analysis/cfg.cpp
+++ b/clang/test/Analysis/cfg.cpp
@@ -144,3 +144,40 @@ void test_deleteArraydtor() {
A *a = new A[5];
delete[] a;
}
+
+
+namespace NoReturnSingleSuccessor {
+ struct A {
+ A();
+ ~A();
+ };
+
+ struct B : public A {
+ B();
+ ~B() __attribute__((noreturn));
+ };
+
+// CHECK: ENTRY
+// CHECK: 1: 1
+// CHECK-NEXT: 2: return
+// CHECK-NEXT: ~B() (Implicit destructor)
+// CHECK-NEXT: Preds (1)
+// CHECK-NEXT: Succs (1): B0
+ int test1(int *x) {
+ B b;
+ if (x)
+ return 1;
+ }
+
+// CHECK: ENTRY
+// CHECK: 1: 1
+// CHECK-NEXT: 2: return
+// CHECK-NEXT: destructor
+// CHECK-NEXT: Preds (1)
+// CHECK-NEXT: Succs (1): B0
+ int test2(int *x) {
+ const A& a = B();
+ if (x)
+ return 1;
+ }
+}
OpenPOWER on IntegriCloud