diff options
55 files changed, 648 insertions, 474 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index 3a51182172..875df3a4ec 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_GR_COREENGINE #include "clang/AST/Expr.h" +#include "clang/Analysis/AnalysisContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" #include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" #include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" @@ -469,6 +470,10 @@ public: const Expr *getTarget() const { return E; } const ProgramState *getState() const { return Pred->State; } + + const LocationContext *getLocationContext() const { + return Pred->getLocationContext(); + } }; class SwitchNodeBuilder { @@ -518,6 +523,10 @@ public: const Expr *getCondition() const { return Condition; } const ProgramState *getState() const { return Pred->State; } + + const LocationContext *getLocationContext() const { + return Pred->getLocationContext(); + } }; class CallEnterNodeBuilder { diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h index 2463e23f5f..c58da3ea52 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_GR_ENVIRONMENT_H #define LLVM_CLANG_GR_ENVIRONMENT_H +#include "clang/Analysis/AnalysisContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/ADT/ImmutableMap.h" @@ -26,15 +27,39 @@ namespace ento { class EnvironmentManager; class SValBuilder; -/// Environment - An immutable map from Stmts to their current -/// symbolic values (SVals). -/// +/// An entry in the environment consists of a Stmt and an LocationContext. +/// This allows the environment to manage context-sensitive bindings, +/// which is essentially for modeling recursive function analysis, among +/// other things. +class EnvironmentEntry : public std::pair<const Stmt*, + const StackFrameContext *> { +public: + EnvironmentEntry(const Stmt *s, const LocationContext *L) + : std::pair<const Stmt*, + const StackFrameContext*>(s, L ? L->getCurrentStackFrame():0) {} + + const Stmt *getStmt() const { return first; } + const LocationContext *getLocationContext() const { return second; } + + /// Profile an EnvironmentEntry for inclusion in a FoldingSet. + static void Profile(llvm::FoldingSetNodeID &ID, + const EnvironmentEntry &E) { + ID.AddPointer(E.getStmt()); + ID.AddPointer(E.getLocationContext()); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, *this); + } +}; + +/// An immutable map from EnvironemntEntries to SVals. class Environment { private: friend class EnvironmentManager; // Type definitions. - typedef llvm::ImmutableMap<const Stmt*,SVal> BindingsTy; + typedef llvm::ImmutableMap<EnvironmentEntry, SVal> BindingsTy; // Data. BindingsTy ExprBindings; @@ -42,18 +67,18 @@ private: Environment(BindingsTy eb) : ExprBindings(eb) {} - SVal lookupExpr(const Stmt *E) const; + SVal lookupExpr(const EnvironmentEntry &E) const; public: typedef BindingsTy::iterator iterator; iterator begin() const { return ExprBindings.begin(); } iterator end() const { return ExprBindings.end(); } - - /// getSVal - Fetches the current binding of the expression in the - /// Environment. - SVal getSVal(const Stmt *Ex, SValBuilder& svalBuilder, - bool useOnlyDirectBindings = false) const; + /// Fetches the current binding of the expression in the + /// Environment. + SVal getSVal(const EnvironmentEntry &E, + SValBuilder &svalBuilder, + bool useOnlyDirectBindings = false) const; /// Profile - Profile the contents of an Environment object for use /// in a FoldingSet. @@ -70,6 +95,12 @@ public: bool operator==(const Environment& RHS) const { return ExprBindings == RHS.ExprBindings; } + + void print(raw_ostream &Out, const char *NL, const char *Sep) const; + +private: + void printAux(raw_ostream &Out, bool printLocations, + const char *NL, const char *Sep) const; }; class EnvironmentManager { @@ -85,17 +116,20 @@ public: return Environment(F.getEmptyMap()); } - /// Bind the value 'V' to the statement 'S'. - Environment bindExpr(Environment Env, const Stmt *S, SVal V, + /// Bind a symbolic value to the given environment entry. + Environment bindExpr(Environment Env, const EnvironmentEntry &E, SVal V, bool Invalidate); - /// Bind the location 'location' and value 'V' to the statement 'S'. This - /// is used when simulating loads/stores. - Environment bindExprAndLocation(Environment Env, const Stmt *S, SVal location, + /// Bind the location 'location' and value 'V' to the specified + /// environment entry. + Environment bindExprAndLocation(Environment Env, + const EnvironmentEntry &E, + SVal location, SVal V); Environment removeDeadBindings(Environment Env, - SymbolReaper &SymReaper, const ProgramState *ST); + SymbolReaper &SymReaper, + const ProgramState *state); }; } // end GR namespace diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 3877cb88b4..f6d49985cc 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -433,8 +433,10 @@ protected: const CallOrObjCMessage &Call, const LocationContext *LC); - const ProgramState *MarkBranch(const ProgramState *St, const Stmt *Terminator, - bool branchTaken); + const ProgramState *MarkBranch(const ProgramState *state, + const Stmt *Terminator, + const LocationContext *LCtx, + bool branchTaken); /// evalBind - Handle the semantics of binding a value to a specific location. /// This method is used by evalStore, VisitDeclStmt, and others. diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h index 500f587e85..bcaf2591cf 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h @@ -95,7 +95,7 @@ public: if (!isInstanceMessage()) return UndefinedVal(); if (const Expr *Ex = getInstanceReceiver()) - return State->getSValAsScalarOrLoc(Ex); + return State->getSValAsScalarOrLoc(Ex, LC); // An instance message with no expression means we are sending to super. // In this case the object reference is the same as 'self'. @@ -141,11 +141,13 @@ public: return isPropertySetter() ? 1 : 0; } - SVal getArgSVal(unsigned i, const ProgramState *state) const { + SVal getArgSVal(unsigned i, + const LocationContext *LCtx, + const ProgramState *state) const { assert(isValid() && "This ObjCMessage is uninitialized!"); assert(i < getNumArgs() && "Invalid index for argument"); if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) - return state->getSVal(msgE->getArg(i)); + return state->getSVal(msgE->getArg(i), LCtx); assert(isPropertySetter()); return SetterArgV; } @@ -207,13 +209,17 @@ class CallOrObjCMessage { llvm::PointerUnion<const CallExpr *, const CXXConstructExpr *> CallE; ObjCMessage Msg; const ProgramState *State; + const LocationContext *LCtx; public: - CallOrObjCMessage(const CallExpr *callE, const ProgramState *state) - : CallE(callE), State(state) {} - CallOrObjCMessage(const CXXConstructExpr *consE, const ProgramState *state) - : CallE(consE), State(state) {} - CallOrObjCMessage(const ObjCMessage &msg, const ProgramState *state) - : CallE((CallExpr *)0), Msg(msg), State(state) {} + CallOrObjCMessage(const CallExpr *callE, const ProgramState *state, + const LocationContext *lctx) + : CallE(callE), State(state), LCtx(lctx) {} + CallOrObjCMessage(const CXXConstructExpr *consE, const ProgramState *state, + const LocationContext *lctx) + : CallE(consE), State(state), LCtx(lctx) {} + CallOrObjCMessage(const ObjCMessage &msg, const ProgramState *state, + const LocationContext *lctx) + : CallE((CallExpr *)0), Msg(msg), State(state), LCtx(lctx) {} QualType getResultType(ASTContext &ctx) const; @@ -272,8 +278,8 @@ public: SVal getArgSVal(unsigned i) const { assert(i < getNumArgs()); if (!CallE) - return Msg.getArgSVal(i, State); - return State->getSVal(getArg(i)); + return Msg.getArgSVal(i, LCtx, State); + return State->getSVal(getArg(i), LCtx); } const Expr *getArg(unsigned i) const { diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index e9d6d6ec96..c3396d4eb1 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -196,12 +196,14 @@ public: /// Create a new state by binding the value 'V' to the statement 'S' in the /// state's environment. - const ProgramState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const; + const ProgramState *BindExpr(const Stmt *S, const LocationContext *LCtx, + SVal V, bool Invalidate = true) const; /// Create a new state by binding the value 'V' and location 'locaton' to the /// statement 'S' in the state's environment. - const ProgramState *bindExprAndLocation(const Stmt *S, SVal location, SVal V) - const; + const ProgramState *bindExprAndLocation(const Stmt *S, + const LocationContext *LCtx, + SVal location, SVal V) const; const ProgramState *bindDecl(const VarRegion *VR, SVal V) const; @@ -248,9 +250,10 @@ public: const llvm::APSInt *getSymVal(SymbolRef sym) const; /// Returns the SVal bound to the statement 'S' in the state's environment. - SVal getSVal(const Stmt *S, bool useOnlyDirectBindings = false) const; + SVal getSVal(const Stmt *S, const LocationContext *LCtx, + bool useOnlyDirectBindings = false) const; - SVal getSValAsScalarOrLoc(const Stmt *Ex) const; + SVal getSValAsScalarOrLoc(const Stmt *Ex, const LocationContext *LCtx) const; SVal getSVal(Loc LV, QualType T = QualType()) const; @@ -290,7 +293,7 @@ public: const MemRegion * const *end) const; /// Create a new state in which the statement is marked as tainted. - const ProgramState* addTaint(const Stmt *S, + const ProgramState* addTaint(const Stmt *S, const LocationContext *LCtx, TaintTagType Kind = TaintTagGeneric) const; /// Create a new state in which the symbol is marked as tainted. @@ -302,7 +305,8 @@ public: TaintTagType Kind = TaintTagGeneric) const; /// Check if the statement is tainted in the current state. - bool isTainted(const Stmt *S, TaintTagType Kind = TaintTagGeneric) const; + bool isTainted(const Stmt *S, const LocationContext *LCtx, + TaintTagType Kind = TaintTagGeneric) const; bool isTainted(SVal V, TaintTagType Kind = TaintTagGeneric) const; bool isTainted(const SymExpr* Sym, TaintTagType Kind = TaintTagGeneric) const; bool isTainted(const MemRegion *Reg, TaintTagType Kind=TaintTagGeneric) const; @@ -361,12 +365,10 @@ public: } // Pretty-printing. - void print(raw_ostream &Out, CFG *C, const char *nl = "\n", + void print(raw_ostream &Out, const char *nl = "\n", const char *sep = "") const; - void dump(CFG &C) const; - - void printDOT(raw_ostream &Out, CFG &C) const; + void printDOT(raw_ostream &Out) const; void dump() const; @@ -647,7 +649,8 @@ public: //===----------------------------------------------------------------------===// inline const VarRegion* ProgramState::getRegion(const VarDecl *D, - const LocationContext *LC) const { + const LocationContext *LC) const +{ return getStateManager().getRegionManager().getVarRegion(D, LC); } @@ -705,16 +708,20 @@ inline const llvm::APSInt *ProgramState::getSymVal(SymbolRef sym) const { return getStateManager().getSymVal(this, sym); } -inline SVal ProgramState::getSVal(const Stmt *Ex, bool useOnlyDirectBindings) const{ - return Env.getSVal(Ex, *getStateManager().svalBuilder, +inline SVal ProgramState::getSVal(const Stmt *Ex, const LocationContext *LCtx, + bool useOnlyDirectBindings) const{ + return Env.getSVal(EnvironmentEntry(Ex, LCtx), + *getStateManager().svalBuilder, useOnlyDirectBindings); } -inline SVal ProgramState::getSValAsScalarOrLoc(const Stmt *S) const { +inline SVal +ProgramState::getSValAsScalarOrLoc(const Stmt *S, + const LocationContext *LCtx) const { if (const Expr *Ex = dyn_cast<Expr>(S)) { QualType T = Ex->getType(); if (Ex->isLValue() || Loc::isLocType(T) || T->isIntegerType()) - return getSVal(S); + return getSVal(S, LCtx); } return UnknownVal(); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h index 32381e7dec..3690b11eef 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -577,7 +577,7 @@ public: bool isLive(SymbolRef sym); bool isLiveRegion(const MemRegion *region); - bool isLive(const Stmt *ExprVal) const; + bool isLive(const Stmt *ExprVal, const LocationContext *LCtx) const; bool isLive(const VarRegion *VR, bool includeStoreBindings = false) const; /// \brief Unconditionally marks a symbol as live. diff --git a/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp b/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp index 7dad2421bf..df5620b803 100644 --- a/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp @@ -38,19 +38,20 @@ void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE, // Fetch the signature of the called function. const ProgramState *state = C.getState(); + const LocationContext *LCtx = C.getLocationContext(); - SVal V = state->getSVal(CE); + SVal V = state->getSVal(CE, LCtx); if (V.isUnknown()) return; // Casting to void? Discard the value. if (expectedResultTy->isVoidType()) { - C.addTransition(state->BindExpr(CE, UnknownVal())); + C.addTransition(state->BindExpr(CE, LCtx, UnknownVal())); return; } - const MemRegion *callee = state->getSVal(CE->getCallee()).getAsRegion(); + const MemRegion *callee = state->getSVal(CE->getCallee(), LCtx).getAsRegion(); if (!callee) return; @@ -82,7 +83,7 @@ void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE, // the cast avoids some assertion failures elsewhere. SValBuilder &svalBuilder = C.getSValBuilder(); V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy); - C.addTransition(state->BindExpr(CE, V)); + C.addTransition(state->BindExpr(CE, LCtx, V)); } } diff --git a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp index 8296eb93c5..a3dc9648f4 100644 --- a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp @@ -34,9 +34,10 @@ public: void AttrNonNullChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { const ProgramState *state = C.getState(); + const LocationContext *LCtx = C.getLocationContext(); // Check if the callee has a 'nonnull' attribute. - SVal X = state->getSVal(CE->getCallee()); + SVal X = state->getSVal(CE->getCallee(), LCtx); const FunctionDecl *FD = X.getAsFunctionDecl(); if (!FD) @@ -55,7 +56,7 @@ void AttrNonNullChecker::checkPreStmt(const CallExpr *CE, if (!Att->isNonNull(idx)) continue; - SVal V = state->getSVal(*I); + SVal V = state->getSVal(*I, LCtx); DefinedSVal *DV = dyn_cast<DefinedSVal>(&V); // If the value is unknown or undefined, we can't perform this check. diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 1f627297ec..fbe4671ddc 100644 --- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -129,7 +129,7 @@ void NilArgChecker::checkPreObjCMessage(ObjCMessage msg, Name == "compare:options:range:locale:" || Name == "componentsSeparatedByCharactersInSet:" || Name == "initWithFormat:") { - if (isNil(msg.getArgSVal(0, C.getState()))) + if (isNil(msg.getArgSVal(0, C.getLocationContext(), C.getState()))) WarnNilArg(C, msg, 0); } } @@ -262,7 +262,8 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE, return; // Get the value of the "theType" argument. - SVal TheTypeVal = state->getSVal(CE->getArg(1)); + const LocationContext *LCtx = C.getLocationContext(); + SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx); // FIXME: We really should allow ranges of valid theType values, and // bifurcate the state appropriately. @@ -280,7 +281,7 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE, // Look at the value of the integer being passed by reference. Essentially // we want to catch cases where the value passed in is not equal |