[analyzer] Improve handling of noreturn destructors

Summary:
The analyzer incorrectly handled noreturn destructors which were hidden inside
function calls. This happened because NoReturnFunctionChecker only listened for
PostStmt events, which are not executed for destructor calls. I've changed it to
listen to PostCall events, which should catch both cases.

Reviewers: jordan_rose

CC: cfe-commits

Differential Revision: http://llvm-reviews.chandlerc.com/D1056

llvm-svn: 185522
This commit is contained in:
Pavel Labath 2013-07-03 08:23:49 +00:00
parent 18c67a158b
commit f77e736844
2 changed files with 27 additions and 13 deletions

View File

@ -26,31 +26,29 @@ using namespace ento;
namespace {
class NoReturnFunctionChecker : public Checker< check::PostStmt<CallExpr>,
class NoReturnFunctionChecker : public Checker< check::PostCall,
check::PostObjCMessage > {
public:
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
void checkPostCall(const CallEvent &CE, CheckerContext &C) const;
void checkPostObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
};
}
void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE,
void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE,
CheckerContext &C) const {
ProgramStateRef state = C.getState();
const Expr *Callee = CE->getCallee();
bool BuildSinks = false;
bool BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE.getDecl()))
BuildSinks = FD->getAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn();
if (!BuildSinks) {
SVal L = state->getSVal(Callee, C.getLocationContext());
const FunctionDecl *FD = L.getAsFunctionDecl();
if (!FD)
return;
const Expr *Callee = CE.getOriginExpr();
if (!BuildSinks && Callee)
BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
if (FD->getAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn())
BuildSinks = true;
else if (const IdentifierInfo *II = FD->getIdentifier()) {
if (!BuildSinks && CE.isGlobalCFunction()) {
if (const IdentifierInfo *II = CE.getCalleeIdentifier()) {
// HACK: Some functions are not marked noreturn, and don't return.
// Here are a few hardwired ones. If this takes too long, we can
// potentially cache these results.

View File

@ -401,3 +401,19 @@ namespace LifetimeExtension {
clang_analyzer_eval(SaveOnVirtualDestruct::lastOutput == 42); // expected-warning{{TRUE}}
}
}
namespace NoReturn {
struct NR {
~NR() __attribute__((noreturn));
};
void f(int **x) {
NR nr;
}
void g() {
int *x;
f(&x);
*x = 47; // no warning
}
}