[cfe-commits] r90755 - in /cfe/trunk: include/clang/Analysis/PathSensitive/Checker.h include/clang/Analysis/PathSensitive/GRExprEngine.h lib/Analysis/CMakeLists.txt lib/Analysis/GRExprEngine.cpp lib/Analysis/GRExprEngineInternalChecks.h lib/Analysis/NoReturnFunctionChecker.cpp
Zhongxing Xu
xuzhongxing at gmail.com
Mon Dec 7 01:17:35 PST 2009
Author: zhongxingxu
Date: Mon Dec 7 03:17:35 2009
New Revision: 90755
URL: http://llvm.org/viewvc/llvm-project?rev=90755&view=rev
Log:
Add EvalCallExpr interface to checker, and migrate the no-return function
handler to this interface.
GRExprEngine::CheckerEvalCall() will return true if one of the checkers has
processed the node. In the future this might return void when we have some
default checker.
Added:
cfe/trunk/lib/Analysis/NoReturnFunctionChecker.cpp
Modified:
cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h
cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
cfe/trunk/lib/Analysis/CMakeLists.txt
cfe/trunk/lib/Analysis/GRExprEngine.cpp
cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.h
Modified: cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h?rev=90755&r1=90754&r2=90755&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h Mon Dec 7 03:17:35 2009
@@ -174,6 +174,14 @@
return EvalNilReceiver(C, ME);
}
+ bool GR_EvalCallExpr(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder,
+ GRExprEngine &Eng, const CallExpr *CE,
+ ExplodedNode *Pred, void *tag) {
+ CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
+ CE);
+ return EvalCallExpr(C, CE);
+ }
+
// FIXME: Remove the 'tag' option.
void GR_VisitBind(ExplodedNodeSet &Dst,
GRStmtNodeBuilder &Builder, GRExprEngine &Eng,
@@ -229,6 +237,10 @@
virtual bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME) {
return false;
}
+
+ virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE) {
+ return false;
+ }
};
} // end clang namespace
Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h?rev=90755&r1=90754&r2=90755&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h Mon Dec 7 03:17:35 2009
@@ -212,6 +212,10 @@
void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
bool isPrevisit);
+ bool CheckerEvalCall(const CallExpr *CE,
+ ExplodedNodeSet &Dst,
+ ExplodedNode *Pred);
+
void CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
ExplodedNodeSet &Dst,
const GRState *state,
Modified: cfe/trunk/lib/Analysis/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=90755&r1=90754&r2=90755&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CMakeLists.txt (original)
+++ cfe/trunk/lib/Analysis/CMakeLists.txt Mon Dec 7 03:17:35 2009
@@ -36,6 +36,7 @@
MallocChecker.cpp
ManagerRegistry.cpp
MemRegion.cpp
+ NoReturnFunctionChecker.cpp
NSAutoreleasePoolChecker.cpp
NSErrorChecker.cpp
PathDiagnostic.cpp
Modified: cfe/trunk/lib/Analysis/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngine.cpp?rev=90755&r1=90754&r2=90755&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngine.cpp Mon Dec 7 03:17:35 2009
@@ -158,6 +158,27 @@
}
}
+// CheckerEvalCall returns true if one of the checkers processed the node.
+// This may return void when all call evaluation logic goes to some checker
+// in the future.
+bool GRExprEngine::CheckerEvalCall(const CallExpr *CE,
+ ExplodedNodeSet &Dst,
+ ExplodedNode *Pred) {
+ bool Evaluated = false;
+
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
+ void *tag = I->first;
+ Checker *checker = I->second;
+
+ if (checker->GR_EvalCallExpr(Dst, *Builder, *this, CE, Pred, tag)) {
+ Evaluated = true;
+ break;
+ }
+ }
+
+ return Evaluated;
+}
+
// FIXME: This is largely copy-paste from CheckerVisit(). Need to
// unify.
void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
@@ -220,6 +241,9 @@
RegisterUndefinedAssignmentChecker(Eng);
RegisterUndefBranchChecker(Eng);
RegisterUndefResultChecker(Eng);
+
+ // This is not a checker yet.
+ RegisterNoReturnFunctionChecker(Eng);
}
GRExprEngine::GRExprEngine(AnalysisManager &mgr)
@@ -1516,45 +1540,6 @@
//===----------------------------------------------------------------------===//
// Transfer function: Function calls.
//===----------------------------------------------------------------------===//
-static void MarkNoReturnFunction(const FunctionDecl *FD, CallExpr *CE,
- const GRState *state,
- GRStmtNodeBuilder *Builder) {
- if (!FD)
- return;
-
- if (FD->getAttr<NoReturnAttr>() ||
- FD->getAttr<AnalyzerNoReturnAttr>())
- Builder->BuildSinks = true;
- else {
- // 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.
- using llvm::StringRef;
- bool BuildSinks
- = llvm::StringSwitch<bool>(StringRef(FD->getIdentifier()->getName()))
- .Case("exit", true)
- .Case("panic", true)
- .Case("error", true)
- .Case("Assert", true)
- // FIXME: This is just a wrapper around throwing an exception.
- // Eventually inter-procedural analysis should handle this easily.
- .Case("ziperr", true)
- .Case("assfail", true)
- .Case("db_error", true)
- .Case("__assert", true)
- .Case("__assert_rtn", true)
- .Case("__assert_fail", true)
- .Case("dtrace_assfail", true)
- .Case("yy_fatal_error", true)
- .Case("_XCAssertionFailureHandler", true)
- .Case("_DTAssertionFailureHandler", true)
- .Case("_TSAssertionFailureHandler", true)
- .Default(false);
-
- if (BuildSinks)
- Builder->BuildSinks = true;
- }
-}
bool GRExprEngine::EvalBuiltinFunction(const FunctionDecl *FD, CallExpr *CE,
ExplodedNode *Pred,
@@ -1666,32 +1651,41 @@
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
const FunctionDecl* FD = L.getAsFunctionDecl();
- MarkNoReturnFunction(FD, CE, state, Builder);
+ ExplodedNodeSet DstTmp3, DstChecker, DstOther;
- // Evaluate the call.
- if (EvalBuiltinFunction(FD, CE, *DI, Dst))
- continue;
+ // If the callee is processed by a checker, skip the rest logic.
+ if (CheckerEvalCall(CE, DstChecker, *DI))
+ DstTmp3 = DstChecker;
+ else {
+ //MarkNoReturnFunction(FD, CE, state, Builder);
- // Dispatch to the plug-in transfer function.
- SaveOr OldHasGen(Builder->HasGeneratedNode);
- Pred = *DI;
+ // Evaluate the call.
+ if (EvalBuiltinFunction(FD, CE, *DI, Dst))
+ continue;
- // Dispatch to transfer function logic to handle the call itself.
- // FIXME: Allow us to chain together transfer functions.
- assert(Builder && "GRStmtNodeBuilder must be defined.");
- ExplodedNodeSet DstTmp;
+ // Dispatch to the plug-in transfer function.
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
+ Pred = *DI;
+
+ // Dispatch to transfer function logic to handle the call itself.
+ // FIXME: Allow us to chain together transfer functions.
+ assert(Builder && "GRStmtNodeBuilder must be defined.");
- if (!EvalOSAtomic(DstTmp, *this, *Builder, CE, L, Pred))
- getTF().EvalCall(DstTmp, *this, *Builder, CE, L, Pred);
-
- // Handle the case where no nodes where generated. Auto-generate that
- // contains the updated state if we aren't generating sinks.
- if (!Builder->BuildSinks && DstTmp.empty() &&
- !Builder->HasGeneratedNode)
- MakeNode(DstTmp, CE, Pred, state);
+ if (!EvalOSAtomic(DstOther, *this, *Builder, CE, L, Pred))
+ getTF().EvalCall(DstOther, *this, *Builder, CE, L, Pred);
+
+ // Handle the case where no nodes where generated. Auto-generate that
+ // contains the updated state if we aren't generating sinks.
+ if (!Builder->BuildSinks && DstTmp3.empty() &&
+ !Builder->HasGeneratedNode)
+ MakeNode(DstOther, CE, Pred, state);
+
+ DstTmp3 = DstOther;
+ }
+
// Perform the post-condition check of the CallExpr.
- CheckerVisit(CE, Dst, DstTmp, false);
+ CheckerVisit(CE, Dst, DstTmp3, false);
}
}
Modified: cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.h?rev=90755&r1=90754&r2=90755&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.h (original)
+++ cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.h Mon Dec 7 03:17:35 2009
@@ -37,5 +37,7 @@
void RegisterUndefBranchChecker(GRExprEngine &Eng);
void RegisterUndefResultChecker(GRExprEngine &Eng);
+void RegisterNoReturnFunctionChecker(GRExprEngine &Eng);
+
} // end clang namespace
#endif
Added: cfe/trunk/lib/Analysis/NoReturnFunctionChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/NoReturnFunctionChecker.cpp?rev=90755&view=auto
==============================================================================
--- cfe/trunk/lib/Analysis/NoReturnFunctionChecker.cpp (added)
+++ cfe/trunk/lib/Analysis/NoReturnFunctionChecker.cpp Mon Dec 7 03:17:35 2009
@@ -0,0 +1,80 @@
+//=== NoReturnFunctionChecker.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines NoReturnFunctionChecker, which evaluates functions that do not
+// return to the caller.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/Checker.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+
+namespace {
+
+class NoReturnFunctionChecker : public Checker {
+public:
+ static void *getTag() { static int tag = 0; return &tag; }
+ virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+
+}
+
+void clang::RegisterNoReturnFunctionChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new NoReturnFunctionChecker());
+}
+
+bool NoReturnFunctionChecker::EvalCallExpr(CheckerContext &C,
+ const CallExpr *CE) {
+ const GRState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = state->getSVal(Callee);
+ const FunctionDecl *FD = L.getAsFunctionDecl();
+ if (!FD)
+ return false;
+
+ bool BuildSinks = false;
+
+ if (FD->getAttr<NoReturnAttr>() || FD->getAttr<AnalyzerNoReturnAttr>())
+ BuildSinks = true;
+ else {
+ // 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.
+ using llvm::StringRef;
+ BuildSinks
+ = llvm::StringSwitch<bool>(StringRef(FD->getIdentifier()->getName()))
+ .Case("exit", true)
+ .Case("panic", true)
+ .Case("error", true)
+ .Case("Assert", true)
+ // FIXME: This is just a wrapper around throwing an exception.
+ // Eventually inter-procedural analysis should handle this easily.
+ .Case("ziperr", true)
+ .Case("assfail", true)
+ .Case("db_error", true)
+ .Case("__assert", true)
+ .Case("__assert_rtn", true)
+ .Case("__assert_fail", true)
+ .Case("dtrace_assfail", true)
+ .Case("yy_fatal_error", true)
+ .Case("_XCAssertionFailureHandler", true)
+ .Case("_DTAssertionFailureHandler", true)
+ .Case("_TSAssertionFailureHandler", true)
+ .Default(false);
+ }
+
+ if (!BuildSinks)
+ return false;
+
+ C.GenerateSink(CE);
+ return true;
+}
More information about the cfe-commits
mailing list