forked from OSchip/llvm-project
[analyzer] Treat C++ 'throw' as a sink.
Our current handling of 'throw' is all CFG-based: it jumps to a 'catch' block if there is one and the function exit block if not. But this doesn't really get the right behavior when a function is inlined: execution will continue on the caller's side, which is always the wrong thing to do. Even within a single function, 'throw' completely skips any destructors that are to be run. This is essentially the same problem as @finally -- a CFGBlock that can have multiple entry points, whose exit points depend on whether it was entered normally or exceptionally. Representing 'throw' as a sink matches our current (non-)handling of @throw. It's not a perfect solution, but it's better than continuing analysis in an inconsistent or even impossible state. <rdar://problem/12113713> llvm-svn: 162157
This commit is contained in:
parent
a97a99736e
commit
a4309c941c
|
@ -607,11 +607,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
|||
case Stmt::AtomicExprClass:
|
||||
// Fall through.
|
||||
|
||||
// Currently all handling of 'throw' just falls to the CFG. We
|
||||
// can consider doing more if necessary.
|
||||
case Stmt::CXXThrowExprClass:
|
||||
// Fall through.
|
||||
|
||||
// Cases we intentionally don't evaluate, since they don't need
|
||||
// to be explicitly evaluated.
|
||||
case Stmt::AddrLabelExprClass:
|
||||
|
@ -886,12 +881,12 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
|||
Bldr.addNodes(Dst);
|
||||
break;
|
||||
|
||||
case Stmt::ObjCAtThrowStmtClass: {
|
||||
case Stmt::ObjCAtThrowStmtClass:
|
||||
case Stmt::CXXThrowExprClass:
|
||||
// FIXME: This is not complete. We basically treat @throw as
|
||||
// an abort.
|
||||
Bldr.generateNode(S, Pred, Pred->getState(), /*IsSink=*/true);
|
||||
break;
|
||||
}
|
||||
|
||||
case Stmt::ReturnStmtClass:
|
||||
Bldr.takeNodes(Pred);
|
||||
|
|
|
@ -21,3 +21,18 @@ int testObjC() {
|
|||
return a; // no-warning
|
||||
}
|
||||
|
||||
|
||||
void inlinedCXX() {
|
||||
clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
|
||||
throw -1;
|
||||
}
|
||||
|
||||
int testCXX() {
|
||||
int a; // uninitialized
|
||||
// FIXME: this should be reported as a leak, because C++ exceptions are
|
||||
// often not fatal.
|
||||
void *mem = malloc(4);
|
||||
inlinedCXX();
|
||||
free(mem);
|
||||
return a; // no-warning
|
||||
}
|
||||
|
|
|
@ -537,7 +537,8 @@ MyEnum rdar10892489_positive() {
|
|||
throw MyEnumValue;
|
||||
} catch (MyEnum e) {
|
||||
int *p = 0;
|
||||
*p = 0xDEADBEEF; // expected-warning {{null}}
|
||||
// FALSE NEGATIVE
|
||||
*p = 0xDEADBEEF; // {{null}}
|
||||
return e;
|
||||
}
|
||||
return MyEnumValue;
|
||||
|
@ -562,7 +563,8 @@ void PR11545_positive() {
|
|||
catch (...)
|
||||
{
|
||||
int *p = 0;
|
||||
*p = 0xDEADBEEF; // expected-warning {{null}}
|
||||
// FALSE NEGATIVE
|
||||
*p = 0xDEADBEEF; // {{null}}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue