aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Core')
-rw-r--r--lib/StaticAnalyzer/Core/CFRefCount.cpp211
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp28
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp104
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineObjC.cpp7
-rw-r--r--lib/StaticAnalyzer/Core/ObjCMessage.cpp6
5 files changed, 124 insertions, 232 deletions
diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp
index 5991e5325f..7991071a54 100644
--- a/lib/StaticAnalyzer/Core/CFRefCount.cpp
+++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp
@@ -41,50 +41,6 @@ using namespace ento;
using llvm::StrInStrNoCase;
namespace {
-class InstanceReceiver {
- ObjCMessage Msg;
- const LocationContext *LC;
-public:
- InstanceReceiver() : LC(0) { }
- InstanceReceiver(const ObjCMessage &msg,
- const LocationContext *lc = 0) : Msg(msg), LC(lc) {}
-
- bool isValid() const {
- return Msg.isValid() && Msg.isInstanceMessage();
- }
- operator bool() const {
- return isValid();
- }
-
- SVal getSValAsScalarOrLoc(const ProgramState *state) {
- assert(isValid());
- // We have an expression for the receiver? Fetch the value
- // of that expression.
- if (const Expr *Ex = Msg.getInstanceReceiver())
- return state->getSValAsScalarOrLoc(Ex);
-
- // Otherwise we are sending a message to super. In this case the
- // object reference is the same as 'self'.
- if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl())
- return state->getSVal(state->getRegion(SelfDecl, LC));
-
- return UnknownVal();
- }
-
- SourceRange getSourceRange() const {
- assert(isValid());
- if (const Expr *Ex = Msg.getInstanceReceiver())
- return Ex->getSourceRange();
-
- // Otherwise we are sending a message to super.
- SourceLocation L = Msg.getSuperLoc();
- assert(L.isValid());
- return SourceRange(L, L);
- }
-};
-}
-
-namespace {
class GenericNodeBuilderRefCount {
StmtNodeBuilder *SNB;
const Stmt *S;
@@ -1651,28 +1607,6 @@ public:
}
const LangOptions& getLangOptions() const { return LOpts; }
-
- // Calls.
-
- void evalCallOrMessage(ExplodedNodeSet &Dst, ExprEngine &Eng,
- StmtNodeBuilder &Builder,
- const CallOrObjCMessage &callOrMsg,
- InstanceReceiver Receiver, const MemRegion *Callee,
- ExplodedNode *Pred, const ProgramState *state);
-
- virtual void evalCall(ExplodedNodeSet &Dst,
- ExprEngine& Eng,
- StmtNodeBuilder& Builder,
- const CallExpr *CE, SVal L,
- ExplodedNode *Pred);
-
-
- virtual void evalObjCMessage(ExplodedNodeSet &Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- ObjCMessage msg,
- ExplodedNode *Pred,
- const ProgramState *state);
};
} // end anonymous namespace
@@ -2439,133 +2373,6 @@ static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) {
return RetTy;
}
-void CFRefCount::evalCallOrMessage(ExplodedNodeSet &Dst, ExprEngine &Eng,
- StmtNodeBuilder &Builder,
- const CallOrObjCMessage &callOrMsg,
- InstanceReceiver Receiver,
- const MemRegion *Callee,
- ExplodedNode *Pred,
- const ProgramState *state) {
-
- SmallVector<const MemRegion*, 10> RegionsToInvalidate;
-
- // Invalidate all instance variables of the receiver of a message.
- // FIXME: We should be able to do better with inter-procedural analysis.
- if (Receiver) {
- SVal V = Receiver.getSValAsScalarOrLoc(state);
- if (const MemRegion *region = V.getAsRegion())
- RegionsToInvalidate.push_back(region);
- }
-
- // Invalidate all instance variables for the callee of a C++ method call.
- // FIXME: We should be able to do better with inter-procedural analysis.
- // FIXME: we can probably do better for const versus non-const methods.
- if (callOrMsg.isCXXCall()) {
- if (const MemRegion *callee = callOrMsg.getCXXCallee().getAsRegion())
- RegionsToInvalidate.push_back(callee);
- }
-
- for (unsigned idx = 0, e = callOrMsg.getNumArgs(); idx != e; ++idx) {
- SVal V = callOrMsg.getArgSVal(idx);
-
- // If we are passing a location wrapped as an integer, unwrap it and
- // invalidate the values referred by the location.
- if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V))
- V = Wrapped->getLoc();
- else if (!isa<Loc>(V))
- continue;
-
- if (const MemRegion *R = V.getAsRegion()) {
- // Invalidate the value of the variable passed by reference.
-
- // Are we dealing with an ElementRegion? If the element type is
- // a basic integer type (e.g., char, int) and the underying region
- // is a variable region then strip off the ElementRegion.
- // FIXME: We really need to think about this for the general case
- // as sometimes we are reasoning about arrays and other times
- // about (char*), etc., is just a form of passing raw bytes.
- // e.g., void *p = alloca(); foo((char*)p);
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- // Checking for 'integral type' is probably too promiscuous, but
- // we'll leave it in for now until we have a systematic way of
- // handling all of these cases. Eventually we need to come up
- // with an interface to StoreManager so that this logic can be
- // approriately delegated to the respective StoreManagers while
- // still allowing us to do checker-specific logic (e.g.,
- // invalidating reference counts), probably via callbacks.
- if (ER->getElementType()->isIntegralOrEnumerationType()) {
- const MemRegion *superReg = ER->getSuperRegion();
- if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
- isa<ObjCIvarRegion>(superReg))
- R = cast<TypedRegion>(superReg);
- }
- // FIXME: What about layers of ElementRegions?
- }
-
- // Mark this region for invalidation. We batch invalidate regions
- // below for efficiency.
- RegionsToInvalidate.push_back(R);
- } else {
- // Nuke all other arguments passed by reference.
- // FIXME: is this necessary or correct? This handles the non-Region
- // cases. Is it ever valid to store to these?
- state = state->unbindLoc(cast<Loc>(V));
- }
- }
-
- // Block calls result in all captured values passed-via-reference to be
- // invalidated.
- if (const BlockDataRegion *BR = dyn_cast_or_null<BlockDataRegion>(Callee))
- RegionsToInvalidate.push_back(BR);
-
- // Invalidate designated regions using the batch invalidation API.
-
- // FIXME: We can have collisions on the conjured symbol if the
- // expression *I also creates conjured symbols. We probably want
- // to identify conjured symbols by an expression pair: the enclosing
- // expression (the context) and the expression itself. This should
- // disambiguate conjured symbols.
- unsigned Count = Builder.getCurrentBlockCount();
- StoreManager::InvalidatedSymbols IS;
-
- const Expr *Ex = callOrMsg.getOriginExpr();
-
- // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate
- // global variables.
- // NOTE: RetainReleaseChecker handles the actual invalidation of symbols.
- state =
- state->invalidateRegions(RegionsToInvalidate,
- Ex, Count, &IS,
- /* invalidateGlobals = */
- Eng.doesInvalidateGlobals(callOrMsg));
-
- Builder.MakeNode(Dst, Ex, Pred, state);
-}
-
-
-void CFRefCount::evalCall(ExplodedNodeSet &Dst,
- ExprEngine& Eng,
- StmtNodeBuilder& Builder,
- const CallExpr *CE, SVal L,
- ExplodedNode *Pred) {
-
- evalCallOrMessage(Dst, Eng, Builder, CallOrObjCMessage(CE, Pred->getState()),
- InstanceReceiver(), L.getAsRegion(), Pred,
- Pred->getState());
-}
-
-void CFRefCount::evalObjCMessage(ExplodedNodeSet &Dst,
- ExprEngine& Eng,
- StmtNodeBuilder& Builder,
- ObjCMessage msg,
- ExplodedNode *Pred,
- const ProgramState *state) {
-
- evalCallOrMessage(Dst, Eng, Builder, CallOrObjCMessage(msg, Pred->getState()),
- InstanceReceiver(msg, Pred->getLocationContext()),
- /* Callee = */ 0, Pred, state);
-}
-
//===----------------------------------------------------------------------===//
// Pieces of the retain/release checker implemented using a CheckerVisitor.
// More pieces of the retain/release checker will be migrated to this interface
@@ -2744,7 +2551,7 @@ public:
void checkPostStmt(const CXXConstructExpr *CE, CheckerContext &C) const;
void checkPostObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const;
void checkSummary(const RetainSummary &Summ, const CallOrObjCMessage &Call,
- InstanceReceiver Receiver, CheckerContext &C) const;
+ CheckerContext &C) const;
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
@@ -3013,7 +2820,7 @@ void RetainReleaseChecker::checkPostStmt(const CallExpr *CE,
if (!Summ)
return;
- checkSummary(*Summ, CallOrObjCMessage(CE, state), InstanceReceiver(), C);
+ checkSummary(*Summ, CallOrObjCMessage(CE, state), C);
}
void RetainReleaseChecker::checkPostStmt(const CXXConstructExpr *CE,
@@ -3030,7 +2837,7 @@ void RetainReleaseChecker::checkPostStmt(const CXXConstructExpr *CE,
return;
const ProgramState *state = C.getState();
- checkSummary(*Summ, CallOrObjCMessage(CE, state), InstanceReceiver(), C);
+ checkSummary(*Summ, CallOrObjCMessage(CE, state), C);
}
void RetainReleaseChecker::checkPostObjCMessage(const ObjCMessage &Msg,
@@ -3052,13 +2859,11 @@ void RetainReleaseChecker::checkPostObjCMessage(const ObjCMessage &Msg,
if (!Summ)
return;
- checkSummary(*Summ, CallOrObjCMessage(Msg, state),
- InstanceReceiver(Msg, Pred->getLocationContext()), C);
+ checkSummary(*Summ, CallOrObjCMessage(Msg, state), C);
}
void RetainReleaseChecker::checkSummary(const RetainSummary &Summ,
const CallOrObjCMessage &CallOrMsg,
- InstanceReceiver Receiver,
CheckerContext &C) const {
const ProgramState *state = C.getState();
@@ -3084,13 +2889,15 @@ void RetainReleaseChecker::checkSummary(const RetainSummary &Summ,
// Evaluate the effect on the message receiver.
bool ReceiverIsTracked = false;
- if (!hasErr && Receiver) {
- if (SymbolRef Sym = Receiver.getSValAsScalarOrLoc(state).getAsLocSymbol()) {
+ if (!hasErr && CallOrMsg.isObjCMessage()) {
+ const LocationContext *LC = C.getPredecessor()->getLocationContext();
+ SVal Receiver = CallOrMsg.getInstanceMessageReceiver(LC);
+ if (SymbolRef Sym = Receiver.getAsLocSymbol()) {
if (const RefVal *T = state->get<RefBindings>(Sym)) {
ReceiverIsTracked = true;
state = updateSymbol(state, Sym, *T, Summ.getReceiverEffect(), hasErr);
if (hasErr) {
- ErrorRange = Receiver.getSourceRange();
+ ErrorRange = CallOrMsg.getReceiverSourceRange();
ErrorSym = Sym;
}
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 579dcb3f51..de3b312234 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -198,17 +198,6 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
#endif
// Default semantics: invalidate all regions passed as arguments.
- SmallVector<const MemRegion*, 10> regionsToInvalidate;
-
- // FIXME: We can have collisions on the conjured symbol if the
- // expression *I also creates conjured symbols. We probably want
- // to identify conjured symbols by an expression pair: the enclosing
- // expression (the context) and the expression itself. This should
- // disambiguate conjured symbols.
- unsigned blockCount = Builder->getCurrentBlockCount();
-
- // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate
- // global variables.
ExplodedNodeSet destCall;
for (ExplodedNodeSet::iterator
@@ -216,23 +205,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
i != e; ++i)
{
ExplodedNode *Pred = *i;
+ const LocationContext *LC = Pred->getLocationContext();
const ProgramState *state = Pred->getState();
- // Accumulate list of regions that are invalidated.
- for (CXXConstructExpr::const_arg_iterator
- ai = E->arg_begin(), ae = E->arg_end();
- ai != ae; ++ai)
- {
- SVal val = state->getSVal(*ai);
- if (const MemRegion *region = val.getAsRegion())
- regionsToInvalidate.push_back(region);
- }
-
- // Invalidate the regions.
- state = state->invalidateRegions(regionsToInvalidate,
- E, blockCount, 0,
- /* invalidateGlobals = */ true);
-
+ state = invalidateArguments(state, CallOrObjCMessage(E, state), LC);
Builder->MakeNode(destCall, E, Pred, state);
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index e49d376d66..7573208744 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -13,6 +13,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "clang/AST/DeclCXX.h"
#include "clang/Analysis/Support/SaveAndRestore.h"
@@ -63,6 +64,100 @@ void ExprEngine::processCallExit(CallExitNodeBuilder &B) {
B.generateNode(state);
}
+const ProgramState *
+ExprEngine::invalidateArguments(const ProgramState *State,
+ const CallOrObjCMessage &Call,
+ const LocationContext *LC) {
+ SmallVector<const MemRegion *, 8> RegionsToInvalidate;
+
+ if (Call.isObjCMessage()) {
+ // Invalidate all instance variables of the receiver of an ObjC message.
+ // FIXME: We should be able to do better with inter-procedural analysis.
+ if (const MemRegion *MR = Call.getInstanceMessageReceiver(LC).getAsRegion())
+ RegionsToInvalidate.push_back(MR);
+
+ } else if (Call.isCXXCall()) {
+ // Invalidate all instance variables for the callee of a C++ method call.
+ // FIXME: We should be able to do better with inter-procedural analysis.
+ // FIXME: We can probably do better for const versus non-const methods.
+ if (const MemRegion *Callee = Call.getCXXCallee().getAsRegion())
+ RegionsToInvalidate.push_back(Callee);
+
+ } else if (Call.isFunctionCall()) {
+ // Block calls invalidate all captured-by-reference values.
+ if (const MemRegion *Callee = Call.getFunctionCallee().getAsRegion()) {
+ if (isa<BlockDataRegion>(Callee))
+ RegionsToInvalidate.push_back(Callee);
+ }
+ }
+
+ for (unsigned idx = 0, e = Call.getNumArgs(); idx != e; ++idx) {
+ SVal V = Call.getArgSVal(idx);
+
+ // If we are passing a location wrapped as an integer, unwrap it and
+ // invalidate the values referred by the location.
+ if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V))
+ V = Wrapped->getLoc();
+ else if (!isa<Loc>(V))
+ continue;
+
+ if (const MemRegion *R = V.getAsRegion()) {
+ // Invalidate the value of the variable passed by reference.
+
+ // Are we dealing with an ElementRegion? If the element type is
+ // a basic integer type (e.g., char, int) and the underying region
+ // is a variable region then strip off the ElementRegion.
+ // FIXME: We really need to think about this for the general case
+ // as sometimes we are reasoning about arrays and other times
+ // about (char*), etc., is just a form of passing raw bytes.
+ // e.g., void *p = alloca(); foo((char*)p);
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ // Checking for 'integral type' is probably too promiscuous, but
+ // we'll leave it in for now until we have a systematic way of
+ // handling all of these cases. Eventually we need to come up
+ // with an interface to StoreManager so that this logic can be
+ // approriately delegated to the respective StoreManagers while
+ // still allowing us to do checker-specific logic (e.g.,
+ // invalidating reference counts), probably via callbacks.
+ if (ER->getElementType()->isIntegralOrEnumerationType()) {
+ const MemRegion *superReg = ER->getSuperRegion();
+ if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
+ isa<ObjCIvarRegion>(superReg))
+ R = cast<TypedRegion>(superReg);
+ }
+ // FIXME: What about layers of ElementRegions?
+ }
+
+ // Mark this region for invalidation. We batch invalidate regions
+ // below for efficiency.
+ RegionsToInvalidate.push_back(R);
+ } else {
+ // Nuke all other arguments passed by reference.
+ // FIXME: is this necessary or correct? This handles the non-Region
+ // cases. Is it ever valid to store to these?
+ State = State->unbindLoc(cast<Loc>(V));
+ }
+ }
+
+ // Invalidate designated regions using the batch invalidation API.
+
+ // FIXME: We can have collisions on the conjured symbol if the
+ // expression *I also creates conjured symbols. We probably want
+ // to identify conjured symbols by an expression pair: the enclosing
+ // expression (the context) and the expression itself. This should
+ // disambiguate conjured symbols.
+ assert(Builder && "Invalidating arguments outside of a statement context");
+ unsigned Count = Builder->getCurrentBlockCount();
+ StoreManager::InvalidatedSymbols IS;
+
+ // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
+ // global variables.
+ return State->invalidateRegions(RegionsToInvalidate,
+ Call.getOriginExpr(), Count,
+ &IS, doesInvalidateGlobals(Call));
+
+}
+
void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
ExplodedNodeSet &dst) {
// Perform the previsit of the CallExpr.
@@ -108,16 +203,19 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
unsigned Count = Builder.getCurrentBlockCount();
SVal RetVal = SVB.getConjuredSymbolVal(0, CE, ResultTy, Count);
- // Generate a new ExplodedNode with the return value set.
+ // Generate a new state with the return value set.
state = state->BindExpr(CE, RetVal);
- Pred = Builder.generateNode(CE, state, Pred);
+
+ // Invalidate the arguments.
+ const LocationContext *LC = Pred->getLocationContext();
+ state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state), LC);
// Then handle everything else.
unsigned oldSize = Dst.size();
SaveOr OldHasGen(Builder.hasGeneratedNode);
// Dispatch to transfer function logic to handle the rest of the call.
- Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred);
+ //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.
diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index 6cfe8cdc93..a80b2bfb7e 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -273,7 +273,12 @@ void ExprEngine::evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg,
// Bind the return value.
state = state->BindExpr(currentStmt, ReturnValue);
+ // Invalidate the arguments (and the receiver)
+ const LocationContext *LC = Pred->getLocationContext();
+ state = invalidateArguments(state, CallOrObjCMessage(msg, state), LC);
+ Builder->MakeNode(Dst, msg.getOriginExpr(), Pred, state);
+
// Now we can handle the other aspects of the message.
- getTF().evalObjCMessage(Dst, *this, *Builder, msg, Pred, state);
+ //getTF().evalObjCMessage(Dst, *this, *Builder, msg, Pred, state);
}
diff --git a/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
index 82b0e7c305..112c468210 100644
--- a/lib/StaticAnalyzer/Core/ObjCMessage.cpp
+++ b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
@@ -150,3 +150,9 @@ SVal CallOrObjCMessage::getCXXCallee() const {
cast<CXXMemberCallExpr>(ActualCall)->getImplicitObjectArgument();
return State->getSVal(callee);
}
+
+SVal
+CallOrObjCMessage::getInstanceMessageReceiver(const LocationContext *LC) const {
+ assert(isObjCMessage());
+ return Msg.getInstanceReceiverSVal(State, LC);
+}