aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Core')
-rw-r--r--lib/StaticAnalyzer/Core/AggExprVisitor.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/CFRefCount.cpp31
-rw-r--r--lib/StaticAnalyzer/Core/CXXExprEngine.cpp111
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp159
-rw-r--r--lib/StaticAnalyzer/Core/ObjCMessage.cpp20
5 files changed, 161 insertions, 162 deletions
diff --git a/lib/StaticAnalyzer/Core/AggExprVisitor.cpp b/lib/StaticAnalyzer/Core/AggExprVisitor.cpp
index e80cf9b4a3..901190d901 100644
--- a/lib/StaticAnalyzer/Core/AggExprVisitor.cpp
+++ b/lib/StaticAnalyzer/Core/AggExprVisitor.cpp
@@ -60,7 +60,7 @@ void AggExprVisitor::VisitCXXConstructExpr(CXXConstructExpr *E) {
}
void AggExprVisitor::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
- Eng.VisitCXXMemberCallExpr(E, Pred, DstSet);
+ Eng.Visit(E, Pred, DstSet);
}
void ExprEngine::VisitAggExpr(const Expr *E, const MemRegion *Dest,
diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp
index 690ffb5876..416e1209ae 100644
--- a/lib/StaticAnalyzer/Core/CFRefCount.cpp
+++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp
@@ -16,6 +16,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
@@ -2680,11 +2681,14 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
// FIXME: We eventually should handle structs and other compound types
// that are returned by value.
- QualType T = callOrMsg.getResultType(Eng.getContext());
- if (Loc::isLocType(T) || (T->isIntegerType() && T->isScalarType())) {
+ // Use the result type from callOrMsg as it automatically adjusts
+ // for methods/functions that return references.
+ QualType resultTy = callOrMsg.getResultType(Eng.getContext());
+ if (Loc::isLocType(resultTy) ||
+ (resultTy->isIntegerType() && resultTy->isScalarType())) {
unsigned Count = Builder.getCurrentBlockCount();
SValBuilder &svalBuilder = Eng.getSValBuilder();
- SVal X = svalBuilder.getConjuredSymbolVal(NULL, Ex, T, Count);
+ SVal X = svalBuilder.getConjuredSymbolVal(NULL, Ex, resultTy, Count);
state = state->BindExpr(Ex, X, false);
}
@@ -2711,9 +2715,12 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
unsigned Count = Builder.getCurrentBlockCount();
SValBuilder &svalBuilder = Eng.getSValBuilder();
SymbolRef Sym = svalBuilder.getConjuredSymbol(Ex, Count);
- QualType RetT = GetReturnType(Ex, svalBuilder.getContext());
+
+ // Use the result type from callOrMsg as it automatically adjusts
+ // for methods/functions that return references.
+ QualType resultTy = callOrMsg.getResultType(Eng.getContext());
state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(),
- RetT));
+ resultTy));
state = state->BindExpr(Ex, svalBuilder.makeLoc(Sym), false);
// FIXME: Add a flag to the checker where allocations are assumed to
@@ -2766,11 +2773,17 @@ void CFRefCount::evalCall(ExplodedNodeSet& Dst,
if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) {
Summ = Summaries.getPersistentStopSummary();
}
- else {
- const FunctionDecl* FD = L.getAsFunctionDecl();
- Summ = !FD ? Summaries.getDefaultSummary() :
- Summaries.getSummary(FD);
+ else if (const FunctionDecl* FD = L.getAsFunctionDecl()) {
+ Summ = Summaries.getSummary(FD);
}
+ else if (const CXXMemberCallExpr *me = dyn_cast<CXXMemberCallExpr>(CE)) {
+ if (const CXXMethodDecl *MD = me->getMethodDecl())
+ Summ = Summaries.getSummary(MD);
+ else
+ Summ = Summaries.getDefaultSummary();
+ }
+ else
+ Summ = Summaries.getDefaultSummary();
assert(Summ);
evalSummary(Dst, Eng, Builder, CE,
diff --git a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
index a71761dab8..b015d4f264 100644
--- a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
@@ -62,6 +62,34 @@ void ExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE,
}
}
+void ExprEngine::evalCallee(const CallExpr *callExpr,
+ const ExplodedNodeSet &src,
+ ExplodedNodeSet &dest) {
+
+ const Expr *callee = 0;
+
+ switch (callExpr->getStmtClass()) {
+ case Stmt::CXXMemberCallExprClass: {
+ // Evaluate the implicit object argument that is the recipient of the
+ // call.
+ callee = cast<CXXMemberCallExpr>(callExpr)->getImplicitObjectArgument();
+
+ // FIXME: handle member pointers.
+ if (!callee)
+ return;
+
+ break;
+ }
+ default: {
+ callee = callExpr->getCallee()->IgnoreParens();
+ break;
+ }
+ }
+
+ for (ExplodedNodeSet::iterator i = src.begin(), e = src.end(); i != e; ++i)
+ Visit(callee, *i, dest);
+}
+
const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXRecordDecl *D,
const StackFrameContext *SFC) {
const Type *T = D->getTypeForDecl();
@@ -169,89 +197,6 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
Dst.Add(N);
}
-void ExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- // Get the method type.
- const FunctionProtoType *FnType =
- MCE->getCallee()->getType()->getAs<FunctionProtoType>();
- assert(FnType && "Method type not available");
-
- // Evaluate explicit arguments with a worklist.
- ExplodedNodeSet argsEvaluated;
- evalArguments(MCE->arg_begin(), MCE->arg_end(), FnType, Pred, argsEvaluated);
-
- // Evaluate the implicit object argument.
- ExplodedNodeSet AllargsEvaluated;
- const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens());
- if (!ME)
- return;
- Expr *ObjArgExpr = ME->getBase();
- for (ExplodedNodeSet::iterator I = argsEvaluated.begin(),
- E = argsEvaluated.end(); I != E; ++I) {
- Visit(ObjArgExpr, *I, AllargsEvaluated);
- }
-
- // Now evaluate the call itself.
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
- assert(MD && "not a CXXMethodDecl?");
- evalMethodCall(MCE, MD, ObjArgExpr, Pred, AllargsEvaluated, Dst);
-}
-
-void ExprEngine::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(C->getCalleeDecl());
- if (!MD) {
- // If the operator doesn't represent a method call treat as regular call.
- VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
- return;
- }
-
- // Determine the type of function we're calling (if available).
- const FunctionProtoType *Proto = NULL;
- QualType FnType = C->getCallee()->IgnoreParens()->getType();
- if (const PointerType *FnTypePtr = FnType->getAs<PointerType>())
- Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>();
-
- // Evaluate arguments treating the first one (object method is called on)
- // as alvalue.
- ExplodedNodeSet argsEvaluated;
- evalArguments(C->arg_begin(), C->arg_end(), Proto, Pred, argsEvaluated, true);
-
- // Now evaluate the call itself.
- evalMethodCall(C, MD, C->getArg(0), Pred, argsEvaluated, Dst);
-}
-
-void ExprEngine::evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD,
- const Expr *ThisExpr, ExplodedNode *Pred,
- ExplodedNodeSet &Src, ExplodedNodeSet &Dst) {
- // Allow checkers to pre-visit the member call.
- ExplodedNodeSet PreVisitChecks;
- getCheckerManager().runCheckersForPreStmt(PreVisitChecks, Src, MCE, *this);
-
- if (!(MD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) {
- // FIXME: conservative method call evaluation.
- getCheckerManager().runCheckersForPostStmt(Dst, PreVisitChecks, MCE, *this);
- return;
- }
-
- const StackFrameContext *SFC = AMgr.getStackFrame(MD,
- Pred->getLocationContext(),
- MCE,
- Builder->getBlock(),
- Builder->getIndex());
- const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC);
- CallEnter Loc(MCE, SFC, Pred->getLocationContext());
- for (ExplodedNodeSet::iterator I = PreVisitChecks.begin(),
- E = PreVisitChecks.end(); I != E; ++I) {
- // Set up 'this' region.
- const GRState *state = GetState(*I);
- state = state->bindLoc(loc::MemRegionVal(ThisR), state->getSVal(ThisExpr));
- Dst.Add(Builder->generateNode(Loc, state, *I));
- }
-}
-
void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
if (CNE->isArray()) {
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index e90864ed36..2facd567b1 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -554,9 +554,10 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
break;
}
- case Stmt::CallExprClass: {
- const CallExpr* C = cast<CallExpr>(S);
- VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
+ case Stmt::CallExprClass:
+ case Stmt::CXXOperatorCallExprClass:
+ case Stmt::CXXMemberCallExprClass: {
+ VisitCallExpr(cast<CallExpr>(S), Pred, Dst);
break;
}
@@ -568,18 +569,6 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
break;
}
- case Stmt::CXXMemberCallExprClass: {
- const CXXMemberCallExpr *MCE = cast<CXXMemberCallExpr>(S);
- VisitCXXMemberCallExpr(MCE, Pred, Dst);
- break;
- }
-
- case Stmt::CXXOperatorCallExprClass: {
- const CXXOperatorCallExpr *C = cast<CXXOperatorCallExpr>(S);
- VisitCXXOperatorCallExpr(C, Pred, Dst);
- break;
- }
-
case Stmt::CXXNewExprClass: {
const CXXNewExpr *NE = cast<CXXNewExpr>(S);
VisitCXXNewExpr(NE, Pred, Dst);
@@ -1554,6 +1543,15 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
ExplodedNode *Pred) {
+ return false;
+
+ // Inlining isn't correct right now because we:
+ // (a) don't generate CallExit nodes.
+ // (b) we need a way to postpone doing post-visits of CallExprs until
+ // the CallExit. This means we need CallExits for the non-inline
+ // cases as well.
+
+#if 0
const GRState *state = GetState(Pred);
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
@@ -1562,6 +1560,29 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
if (!FD)
return false;
+ // Specially handle CXXMethods.
+ const CXXMethodDecl *methodDecl = 0;
+
+ switch (CE->getStmtClass()) {
+ default: break;
+ case Stmt::CXXOperatorCallExprClass: {
+ const CXXOperatorCallExpr *opCall = cast<CXXOperatorCallExpr>(CE);
+ methodDecl =
+ llvm::dyn_cast_or_null<CXXMethodDecl>(opCall->getCalleeDecl());
+ break;
+ }
+ case Stmt::CXXMemberCallExprClass: {
+ const CXXMemberCallExpr *memberCall = cast<CXXMemberCallExpr>(CE);
+ const MemberExpr *memberExpr =
+ cast<MemberExpr>(memberCall->getCallee()->IgnoreParens());
+ methodDecl = cast<CXXMethodDecl>(memberExpr->getMemberDecl());
+ break;
+ }
+ }
+
+
+
+
// Check if the function definition is in the same translation unit.
if (FD->hasBody(FD)) {
const StackFrameContext *stackFrame =
@@ -1589,14 +1610,15 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
Dst.Add(N);
return true;
}
+
+ // Generate the CallExit node.
return false;
+#endif
}
-void ExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred,
- CallExpr::const_arg_iterator AI,
- CallExpr::const_arg_iterator AE,
- ExplodedNodeSet& Dst) {
+void ExprEngine::VisitCallExpr(const CallExpr* CE, ExplodedNode* Pred,
+ ExplodedNodeSet& dst) {
// Determine the type of function we're calling (if available).
const FunctionProtoType *Proto = NULL;
@@ -1604,73 +1626,78 @@ void ExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred,
if (const PointerType *FnTypePtr = FnType->getAs<PointerType>())
Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>();
- // Evaluate the arguments.
- ExplodedNodeSet ArgsEvaluated;
- evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, ArgsEvaluated);
-
- // Now process the call itself.
- ExplodedNodeSet DstTmp;
- const Expr* Callee = CE->getCallee()->IgnoreParens();
-
- for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(),
- NE=ArgsEvaluated.end(); NI != NE; ++NI) {
- // Evaluate the callee.
- ExplodedNodeSet DstTmp2;
- Visit(Callee, *NI, DstTmp2);
- // Perform the previsit of the CallExpr, storing the results in DstTmp.
- getCheckerManager().runCheckersForPreStmt(DstTmp, DstTmp2, CE, *this);
+ // Should the first argument be evaluated as an lvalue?
+ bool firstArgumentAsLvalue = false;
+ switch (CE->getStmtClass()) {
+ case Stmt::CXXOperatorCallExprClass:
+ firstArgumentAsLvalue = true;
+ break;
+ default:
+ break;
}
-
+
+ // Evaluate the arguments.
+ ExplodedNodeSet dstArgsEvaluated;
+ evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, dstArgsEvaluated,
+ firstArgumentAsLvalue);
+
+ // Evaluate the callee.
+ ExplodedNodeSet dstCalleeEvaluated;
+ evalCallee(CE, dstArgsEvaluated, dstCalleeEvaluated);
+
+ // Perform the previsit of the CallExpr.
+ ExplodedNodeSet dstPreVisit;
+ getCheckerManager().runCheckersForPreStmt(dstPreVisit, dstCalleeEvaluated,
+ CE, *this);
+
+ // Now evaluate the call itself.
class DefaultEval : public GraphExpander {
ExprEngine &Eng;
const CallExpr *CE;
public:
- bool Inlined;
DefaultEval(ExprEngine &eng, const CallExpr *ce)
- : Eng(eng), CE(ce), Inlined(false) { }
+ : Eng(eng), CE(ce) {}
virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ // Should we inline the call?
if (Eng.getAnalysisManager().shouldInlineCall() &&
Eng.InlineCall(Dst, CE, Pred)) {
- Inlined = true;
- } else {
- StmtNodeBuilder &Builder = Eng.getBuilder();
- assert(&Builder && "StmtNodeBuilder must be defined.");
-
- // Dispatch to the plug-in transfer function.
- unsigned oldSize = Dst.size();
- SaveOr OldHasGen(Builder.hasGeneratedNode);
-
- // Dispatch to transfer function logic to handle the call itself.
- const Expr* Callee = CE->getCallee()->IgnoreParens();
- const GRState* state = Eng.GetState(Pred);
- SVal L = state->getSVal(Callee);
- Eng.getTF().evalCall(Dst, Eng, 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 && Dst.size() == oldSize &&
- !Builder.hasGeneratedNode)
- Eng.MakeNode(Dst, CE, Pred, state);
+ return;
}
+
+ StmtNodeBuilder &Builder = Eng.getBuilder();
+ assert(&Builder && "StmtNodeBuilder must be defined.");
+
+ // Dispatch to the plug-in transfer function.
+ unsigned oldSize = Dst.size();
+ SaveOr OldHasGen(Builder.hasGeneratedNode);
+
+ // Dispatch to transfer function logic to handle the call itself.
+ const Expr* Callee = CE->getCallee()->IgnoreParens();
+ const GRState* state = Eng.GetState(Pred);
+ SVal L = state->getSVal(Callee);
+ Eng.getTF().evalCall(Dst, Eng, 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 && Dst.size() == oldSize &&
+ !Builder.hasGeneratedNode)
+ Eng.MakeNode(Dst, CE, Pred, state);
}
};
// Finally, evaluate the function call. We try each of the checkers
// to see if the can evaluate the function call.
- ExplodedNodeSet DstTmp3;
+ ExplodedNodeSet dstCallEvaluated;
DefaultEval defEval(*this, CE);
-
- getCheckerManager().runCheckersForEvalCall(DstTmp3, DstTmp, CE,
- *this, &defEval);
-
- // Callee is inlined. We shouldn't do post call checking.
- if (defEval.Inlined)
- return;
+ getCheckerManager().runCheckersForEvalCall(dstCallEvaluated,
+ dstPreVisit,
+ CE, *this, &defEval);
// Finally, perform the post-condition check of the CallExpr and store
// the created nodes in 'Dst'.
- getCheckerManager().runCheckersForPostStmt(Dst, DstTmp3, CE, *this);
+ getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE,
+ *this);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
index b2272968bb..c44d36ae49 100644
--- a/lib/StaticAnalyzer/Core/ObjCMessage.cpp
+++ b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
@@ -109,13 +109,27 @@ const Expr *ObjCMessage::getArgExpr(unsigned i) const {
}
QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const {
+ QualType resultTy;
+ bool isLVal = false;
+
if (CallE) {
+ isLVal = CallE->isLValue();
const Expr *Callee = CallE->getCallee();
if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl())
- return FD->getResultType();
- return CallE->getType();
+ resultTy = FD->getResultType();
+ else
+ resultTy = CallE->getType();
+ }
+ else {
+ isLVal = isa<ObjCMessageExpr>(Msg.getOriginExpr()) &&
+ Msg.getOriginExpr()->isLValue();
+ resultTy = Msg.getResultType(ctx);
}
- return Msg.getResultType(ctx);
+
+ if (isLVal)
+ resultTy = ctx.getPointerType(resultTy);
+
+ return resultTy;
}
SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const {