aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/StaticAnalyzer/CFRefCount.cpp125
-rw-r--r--lib/StaticAnalyzer/CMakeLists.txt1
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp57
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp91
-rw-r--r--lib/StaticAnalyzer/Checkers/ExprEngine.cpp57
-rw-r--r--lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp14
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/ObjCMessage.cpp99
8 files changed, 289 insertions, 171 deletions
diff --git a/lib/StaticAnalyzer/CFRefCount.cpp b/lib/StaticAnalyzer/CFRefCount.cpp
index d4bed35317..5cc4a3c3ee 100644
--- a/lib/StaticAnalyzer/CFRefCount.cpp
+++ b/lib/StaticAnalyzer/CFRefCount.cpp
@@ -40,14 +40,15 @@ using llvm::StrInStrNoCase;
namespace {
class InstanceReceiver {
- const ObjCMessageExpr *ME;
+ ObjCMessage Msg;
const LocationContext *LC;
public:
- InstanceReceiver(const ObjCMessageExpr *me = 0,
- const LocationContext *lc = 0) : ME(me), LC(lc) {}
+ InstanceReceiver() : LC(0) { }
+ InstanceReceiver(const ObjCMessage &msg,
+ const LocationContext *lc = 0) : Msg(msg), LC(lc) {}
bool isValid() const {
- return ME && ME->isInstanceMessage();
+ return Msg.isValid() && Msg.isInstanceMessage();
}
operator bool() const {
return isValid();
@@ -57,7 +58,7 @@ public:
assert(isValid());
// We have an expression for the receiver? Fetch the value
// of that expression.
- if (const Expr *Ex = ME->getInstanceReceiver())
+ if (const Expr *Ex = Msg.getInstanceReceiver())
return state->getSValAsScalarOrLoc(Ex);
// Otherwise we are sending a message to super. In this case the
@@ -70,11 +71,11 @@ public:
SourceRange getSourceRange() const {
assert(isValid());
- if (const Expr *Ex = ME->getInstanceReceiver())
+ if (const Expr *Ex = Msg.getInstanceReceiver())
return Ex->getSourceRange();
// Otherwise we are sending a message to super.
- SourceLocation L = ME->getSuperLoc();
+ SourceLocation L = Msg.getSuperLoc();
assert(L.isValid());
return SourceRange(L, L);
}
@@ -798,14 +799,14 @@ public:
RetainSummary* getSummary(const FunctionDecl* FD);
- RetainSummary *getInstanceMethodSummary(const ObjCMessageExpr *ME,
+ RetainSummary *getInstanceMethodSummary(const ObjCMessage &msg,
const GRState *state,
const LocationContext *LC);
- RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME,
+ RetainSummary* getInstanceMethodSummary(const ObjCMessage &msg,
const ObjCInterfaceDecl* ID) {
- return getInstanceMethodSummary(ME->getSelector(), 0,
- ID, ME->getMethodDecl(), ME->getType());
+ return getInstanceMethodSummary(msg.getSelector(), 0,
+ ID, msg.getMethodDecl(), msg.getType(Ctx));
}
RetainSummary* getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName,
@@ -818,23 +819,15 @@ public:
const ObjCMethodDecl *MD,
QualType RetTy);
- RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) {
- ObjCInterfaceDecl *Class = 0;
- switch (ME->getReceiverKind()) {
- case ObjCMessageExpr::Class:
- case ObjCMessageExpr::SuperClass:
- Class = ME->getReceiverInterface();
- break;
-
- case ObjCMessageExpr::Instance:
- case ObjCMessageExpr::SuperInstance:
- break;
- }
+ RetainSummary *getClassMethodSummary(const ObjCMessage &msg) {
+ const ObjCInterfaceDecl *Class = 0;
+ if (!msg.isInstanceMessage())
+ Class = msg.getReceiverInterface();
- return getClassMethodSummary(ME->getSelector(),
+ return getClassMethodSummary(msg.getSelector(),
Class? Class->getIdentifier() : 0,
Class,
- ME->getMethodDecl(), ME->getType());
+ msg.getMethodDecl(), msg.getType(Ctx));
}
/// getMethodSummary - This version of getMethodSummary is used to query
@@ -1310,13 +1303,13 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
}
RetainSummary*
-RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
+RetainSummaryManager::getInstanceMethodSummary(const ObjCMessage &msg,
const GRState *state,
const LocationContext *LC) {
// We need the type-information of the tracked receiver object
// Retrieve it from the state.
- const Expr *Receiver = ME->getInstanceReceiver();
+ const Expr *Receiver = msg.getInstanceReceiver();
const ObjCInterfaceDecl* ID = 0;
// FIXME: Is this really working as expected? There are cases where
@@ -1344,12 +1337,12 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
}
} else {
// FIXME: Hack for 'super'.
- ID = ME->getReceiverInterface();
+ ID = msg.getReceiverInterface();
}
// FIXME: The receiver could be a reference to a class, meaning that
// we should use the class method.
- RetainSummary *Summ = getInstanceMethodSummary(ME, ID);
+ RetainSummary *Summ = getInstanceMethodSummary(msg, ID);
// Special-case: are we sending a mesage to "self"?
// This is a hack. When we have full-IP this should be removed.
@@ -1693,10 +1686,10 @@ public:
ExprEngine& Eng,
StmtNodeBuilder& Builder,
const Expr* Ex,
+ const CallOrObjCMessage &callOrMsg,
InstanceReceiver Receiver,
const RetainSummary& Summ,
const MemRegion *Callee,
- ConstExprIterator arg_beg, ConstExprIterator arg_end,
ExplodedNode* Pred, const GRState *state);
virtual void evalCall(ExplodedNodeSet& Dst,
@@ -1706,12 +1699,12 @@ public:
ExplodedNode* Pred);
- virtual void evalObjCMessageExpr(ExplodedNodeSet& Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- const ObjCMessageExpr* ME,
- ExplodedNode* Pred,
- const GRState *state);
+ virtual void evalObjCMessage(ExplodedNodeSet& Dst,
+ ExprEngine& Engine,
+ StmtNodeBuilder& Builder,
+ ObjCMessage msg,
+ ExplodedNode* Pred,
+ const GRState *state);
// Stores.
virtual void evalBind(StmtNodeBuilderRef& B, SVal location, SVal val);
@@ -2477,16 +2470,14 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
ExprEngine& Eng,
StmtNodeBuilder& Builder,
const Expr* Ex,
+ const CallOrObjCMessage &callOrMsg,
InstanceReceiver Receiver,
const RetainSummary& Summ,
const MemRegion *Callee,
- ConstExprIterator arg_beg,
- ConstExprIterator arg_end,
ExplodedNode* Pred, const GRState *state) {
// Evaluate the effect of the arguments.
RefVal::Kind hasErr = (RefVal::Kind) 0;
- unsigned idx = 0;
SourceRange ErrorRange;
SymbolRef ErrorSym = 0;
@@ -2498,8 +2489,8 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
// done an invalidation pass.
llvm::DenseSet<SymbolRef> WhitelistedSymbols;
- for (ConstExprIterator I = arg_beg; I != arg_end; ++I, ++idx) {
- SVal V = state->getSValAsScalarOrLoc(*I);
+ for (unsigned idx = 0, e = callOrMsg.getNumArgs(); idx != e; ++idx) {
+ SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx);
SymbolRef Sym = V.getAsLocSymbol();
if (Sym)
@@ -2507,7 +2498,7 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
WhitelistedSymbols.insert(Sym);
state = Update(state, Sym, *T, Summ.getArg(idx), hasErr);
if (hasErr) {
- ErrorRange = (*I)->getSourceRange();
+ ErrorRange = callOrMsg.getArgSourceRange(idx);
ErrorSym = Sym;
break;
}
@@ -2650,19 +2641,7 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
// FIXME: We eventually should handle structs and other compound types
// that are returned by value.
- QualType T = Ex->getType();
-
- // For CallExpr, use the result type to know if it returns a reference.
- if (const CallExpr *CE = dyn_cast<CallExpr>(Ex)) {
- const Expr *Callee = CE->getCallee();
- if (const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl())
- T = FD->getResultType();
- }
- else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(Ex)) {
- if (const ObjCMethodDecl *MD = ME->getMethodDecl())
- T = MD->getResultType();
- }
-
+ QualType T = callOrMsg.getResultType(Eng.getContext());
if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
unsigned Count = Builder.getCurrentBlockCount();
SValBuilder &svalBuilder = Eng.getSValBuilder();
@@ -2675,9 +2654,8 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
case RetEffect::Alias: {
unsigned idx = RE.getIndex();
- assert (arg_end >= arg_beg);
- assert (idx < (unsigned) (arg_end - arg_beg));
- SVal V = state->getSValAsScalarOrLoc(*(arg_beg+idx));
+ assert (idx < callOrMsg.getNumArgs());
+ SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx);
state = state->BindExpr(Ex, V, false);
break;
}
@@ -2756,25 +2734,28 @@ void CFRefCount::evalCall(ExplodedNodeSet& Dst,
}
assert(Summ);
- evalSummary(Dst, Eng, Builder, CE, 0, *Summ, L.getAsRegion(),
- CE->arg_begin(), CE->arg_end(), Pred, Builder.GetState(Pred));
+ evalSummary(Dst, Eng, Builder, CE,
+ CallOrObjCMessage(CE, Builder.GetState(Pred)),
+ InstanceReceiver(), *Summ,L.getAsRegion(),
+ Pred, Builder.GetState(Pred));
}
-void CFRefCount::evalObjCMessageExpr(ExplodedNodeSet& Dst,
- ExprEngine& Eng,
- StmtNodeBuilder& Builder,
- const ObjCMessageExpr* ME,
- ExplodedNode* Pred,
- const GRState *state) {
+void CFRefCount::evalObjCMessage(ExplodedNodeSet& Dst,
+ ExprEngine& Eng,
+ StmtNodeBuilder& Builder,
+ ObjCMessage msg,
+ ExplodedNode* Pred,
+ const GRState *state) {
RetainSummary *Summ =
- ME->isInstanceMessage()
- ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext())
- : Summaries.getClassMethodSummary(ME);
+ msg.isInstanceMessage()
+ ? Summaries.getInstanceMethodSummary(msg, state,Pred->getLocationContext())
+ : Summaries.getClassMethodSummary(msg);
assert(Summ && "RetainSummary is null");
- evalSummary(Dst, Eng, Builder, ME,
- InstanceReceiver(ME, Pred->getLocationContext()), *Summ, NULL,
- ME->arg_begin(), ME->arg_end(), Pred, state);
+ evalSummary(Dst, Eng, Builder, msg.getOriginExpr(),
+ CallOrObjCMessage(msg, Builder.GetState(Pred)),
+ InstanceReceiver(msg, Pred->getLocationContext()), *Summ, NULL,
+ Pred, state);
}
namespace {
diff --git a/lib/StaticAnalyzer/CMakeLists.txt b/lib/StaticAnalyzer/CMakeLists.txt
index cf81e1d5ad..352138599e 100644
--- a/lib/StaticAnalyzer/CMakeLists.txt
+++ b/lib/StaticAnalyzer/CMakeLists.txt
@@ -24,6 +24,7 @@ add_clang_library(clangStaticAnalyzerCore
HTMLDiagnostics.cpp
ManagerRegistry.cpp
MemRegion.cpp
+ ObjCMessage.cpp
PathDiagnostic.cpp
PlistDiagnostics.cpp
RangeConstraintManager.cpp
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 3910196265..8fa7e24cab 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -42,14 +42,14 @@ public:
// Utility functions.
//===----------------------------------------------------------------------===//
-static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
- if (ObjCInterfaceDecl *ID = ME->getReceiverInterface())
+static const ObjCInterfaceType* GetReceiverType(const ObjCMessage &msg) {
+ if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
return ID->getTypeForDecl()->getAs<ObjCInterfaceType>();
return NULL;
}
-static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
- if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME))
+static const char* GetReceiverNameType(const ObjCMessage &msg) {
+ if (const ObjCInterfaceType *ReceiverType = GetReceiverType(msg))
return ReceiverType->getDecl()->getIdentifier()->getNameStart();
return NULL;
}
@@ -69,16 +69,16 @@ static inline bool isNil(SVal X) {
namespace {
class NilArgChecker : public CheckerVisitor<NilArgChecker> {
APIMisuse *BT;
- void WarnNilArg(CheckerContext &C, const ObjCMessageExpr* ME, unsigned Arg);
+ void WarnNilArg(CheckerContext &C, const ObjCMessage &msg, unsigned Arg);
public:
NilArgChecker() : BT(0) {}
static void *getTag() { static int x = 0; return &x; }
- void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+ void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
};
}
void NilArgChecker::WarnNilArg(CheckerContext &C,
- const clang::ObjCMessageExpr *ME,
+ const ObjCMessage &msg,
unsigned int Arg)
{
if (!BT)
@@ -87,24 +87,24 @@ void NilArgChecker::WarnNilArg(CheckerContext &C,
if (ExplodedNode *N = C.generateSink()) {
llvm::SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
- os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
- << ME->getSelector().getAsString() << "' cannot be nil";
+ os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
+ << msg.getSelector().getAsString() << "' cannot be nil";
RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
- R->addRange(ME->getArg(Arg)->getSourceRange());
+ R->addRange(msg.getArgSourceRange(Arg));
C.EmitReport(R);
}
}
-void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C,
- const ObjCMessageExpr *ME)
+void NilArgChecker::preVisitObjCMessage(CheckerContext &C,
+ ObjCMessage msg)
{
- const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
+ const ObjCInterfaceType *ReceiverType = GetReceiverType(msg);
if (!ReceiverType)
return;
if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
- Selector S = ME->getSelector();
+ Selector S = msg.getSelector();
if (S.isUnarySelector())
return;
@@ -127,8 +127,8 @@ void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C,
Name == "compare:options:range:locale:" ||
Name == "componentsSeparatedByCharactersInSet:" ||
Name == "initWithFormat:") {
- if (isNil(C.getState()->getSVal(ME->getArg(0))))
- WarnNilArg(C, ME, 0);
+ if (isNil(msg.getArgSVal(0, C.getState())))
+ WarnNilArg(C, msg, 0);
}
}
}
@@ -441,12 +441,12 @@ public:
static void *getTag() { static int x = 0; return &x; }
- void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+ void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
};
}
-void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
- const ObjCMessageExpr *ME) {
+void ClassReleaseChecker::preVisitObjCMessage(CheckerContext &C,
+ ObjCMessage msg) {
if (!BT) {
BT = new APIMisuse("message incorrectly sent to class instead of class "
@@ -459,21 +459,12 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
drainS = GetNullarySelector("drain", Ctx);
}
- ObjCInterfaceDecl *Class = 0;
-
- switch (ME->getReceiverKind()) {
- case ObjCMessageExpr::Class:
- Class = ME->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
- break;
- case ObjCMessageExpr::SuperClass:
- Class = ME->getSuperType()->getAs<ObjCObjectType>()->getInterface();
- break;
- case ObjCMessageExpr::Instance:
- case ObjCMessageExpr::SuperInstance:
+ if (msg.isInstanceMessage())
return;
- }
+ const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
+ assert(Class);
- Selector S = ME->getSelector();
+ Selector S = msg.getSelector();
if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
return;
@@ -486,7 +477,7 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
<< "' and not the class directly";
RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
- report->addRange(ME->getSourceRange());
+ report->addRange(msg.getSourceRange());
C.EmitReport(report);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 2998406da0..e6a40bb597 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -41,19 +41,21 @@ public:
}
void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
- void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
- bool evalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
+ void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
+ bool evalNilReceiver(CheckerContext &C, ObjCMessage msg);
private:
- bool PreVisitProcessArg(CheckerContext &C, const Expr *Ex,
- const char *BT_desc, BugType *&BT);
+ void PreVisitProcessArgs(CheckerContext &C, CallOrObjCMessage callOrMsg,
+ const char *BT_desc, BugType *&BT);
+ bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange,
+ const Expr *argEx, const char *BT_desc, BugType *&BT);
void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
- void emitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
+ void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg,
ExplodedNode *N);
void HandleNilReceiver(CheckerContext &C, const GRState *state,
- const ObjCMessageExpr *ME);
+ ObjCMessage msg);
void LazyInit_BT(const char *desc, BugType *&BT) {
if (!BT)
@@ -78,21 +80,32 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
C.EmitReport(R);
}
+void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C,
+ CallOrObjCMessage callOrMsg,
+ const char *BT_desc,
+ BugType *&BT) {
+ for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i)
+ if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i),
+ callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i),
+ BT_desc, BT))
+ return;
+}
+
bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
- const Expr *Ex,
+ SVal V, SourceRange argRange,
+ const Expr *argEx,
const char *BT_desc,
BugType *&BT) {
- const SVal &V = C.getState()->getSVal(Ex);
-
if (V.isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
LazyInit_BT(BT_desc, BT);
// Generate a report for this bug.
EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
- R->addRange(Ex->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+ R->addRange(argRange);
+ if (argEx)
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, argEx);
C.EmitReport(R);
}
return true;
@@ -172,7 +185,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
// Generate a report for this bug.
EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N);
- R->addRange(Ex->getSourceRange());
+ R->addRange(argRange);
// FIXME: enhance track back for uninitialized value for arbitrary
// memregions
@@ -206,21 +219,18 @@ void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
EmitBadCall(BT_call_null, C, CE);
}
- for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
- I != E; ++I)
- if (PreVisitProcessArg(C, *I,
- "Function call argument is an uninitialized value",
- BT_call_arg))
- return;
+ PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState()),
+ "Function call argument is an uninitialized value",
+ BT_call_arg);
}
-void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
- const ObjCMessageExpr *ME) {
+void CallAndMessageChecker::preVisitObjCMessage(CheckerContext &C,
+ ObjCMessage msg) {
const GRState *state = C.getState();
// FIXME: Handle 'super'?
- if (const Expr *receiver = ME->getInstanceReceiver())
+ if (const Expr *receiver = msg.getInstanceReceiver())
if (state->getSVal(receiver).isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_msg_undef)
@@ -237,22 +247,19 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
}
// Check for any arguments that are uninitialized/undefined.
- for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
- E = ME->arg_end(); I != E; ++I)
- if (PreVisitProcessArg(C, *I,
- "Argument in message expression "
- "is an uninitialized value", BT_msg_arg))
- return;
+ PreVisitProcessArgs(C, CallOrObjCMessage(msg, state),
+ "Argument in message expression "
+ "is an uninitialized value", BT_msg_arg);
}
bool CallAndMessageChecker::evalNilReceiver(CheckerContext &C,
- const ObjCMessageExpr *ME) {
- HandleNilReceiver(C, C.getState(), ME);
+ ObjCMessage msg) {
+ HandleNilReceiver(C, C.getState(), msg);
return true; // Nil receiver is not handled elsewhere.
}
void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
- const ObjCMessageExpr *ME,
+ const ObjCMessage &msg,
ExplodedNode *N) {
if (!BT_msg_ret)
@@ -262,12 +269,12 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
llvm::SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
- os << "The receiver of message '" << ME->getSelector().getAsString()
+ os << "The receiver of message '" << msg.getSelector().getAsString()
<< "' is nil and returns a value of type '"
- << ME->getType().getAsString() << "' that will be garbage";
+ << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage";
EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
- if (const Expr *receiver = ME->getInstanceReceiver()) {
+ if (const Expr *receiver = msg.getInstanceReceiver()) {
report->addRange(receiver->getSourceRange());
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
receiver);
@@ -284,22 +291,22 @@ static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
const GRState *state,
- const ObjCMessageExpr *ME) {
+ ObjCMessage msg) {
+ ASTContext &Ctx = C.getASTContext();
// Check the return type of the message expression. A message to nil will
// return different values depending on the return type and the architecture.
- QualType RetTy = ME->getType();
+ QualType RetTy = msg.getType(Ctx);
- ASTContext &Ctx = C.getASTContext();
CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
if (CanRetTy->isStructureOrClassType()) {
// FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
// have the "use of undefined value" be smarter about where the
// undefined value came from.
- if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
+ if (C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())){
if (ExplodedNode* N = C.generateSink(state))
- emitNilReceiverBug(C, ME, N);
+ emitNilReceiverBug(C, msg, N);
return;
}
@@ -311,7 +318,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
// Other cases: check if the return type is smaller than void*.
if (CanRetTy != Ctx.VoidTy &&
- C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
+ C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())) {
// Compute: sizeof(void *) and sizeof(return type)
const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
@@ -324,7 +331,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
Ctx.LongLongTy == CanRetTy ||
Ctx.UnsignedLongLongTy == CanRetTy))) {
if (ExplodedNode* N = C.generateSink(state))
- emitNilReceiverBug(C, ME, N);
+ emitNilReceiverBug(C, msg, N);
return;
}
@@ -341,8 +348,8 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
// it most likely isn't nil. We should assume the semantics
// of this case unless we have *a lot* more knowledge.
//
- SVal V = C.getSValBuilder().makeZeroVal(ME->getType());
- C.generateNode(state->BindExpr(ME, V));
+ SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
+ C.generateNode(state->BindExpr(msg.getOriginExpr(), V));
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
index a022562a12..6932f4a717 100644
--- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
@@ -145,10 +145,49 @@ void ExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst,
// automatically.
}
-void ExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
- ExplodedNodeSet &Dst,
- const GRState *state,
- ExplodedNode *Pred) {
+void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg,
+ ExplodedNodeSet &Dst,
+ ExplodedNodeSet &Src,
+ bool isPrevisit) {
+
+ if (Checkers.empty()) {
+ Dst.insert(Src);
+ return;
+ }
+
+ ExplodedNodeSet Tmp;
+ ExplodedNodeSet *PrevSet = &Src;
+
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
+ {
+ ExplodedNodeSet *CurrSet = 0;
+ if (I+1 == E)
+ CurrSet = &Dst;
+ else {
+ CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
+ CurrSet->clear();
+ }
+
+ void *tag = I->first;
+ Checker *checker = I->second;
+
+ for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
+ NI != NE; ++NI)
+ checker->GR_visitObjCMessage(*CurrSet, *Builder, *this, msg,
+ *NI, tag, isPrevisit);
+
+ // Update which NodeSet is the current one.
+ PrevSet = CurrSet;
+ }
+
+ // Don't autotransition. The CheckerContext objects should do this
+ // automatically.
+}
+
+void ExprEngine::CheckerEvalNilReceiver(const ObjCMessage &msg,
+ ExplodedNodeSet &Dst,
+ const GRState *state,
+ ExplodedNode *Pred) {
bool evaluated = false;
ExplodedNodeSet DstTmp;
@@ -156,7 +195,7 @@ void ExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
void *tag = I->first;
Checker *checker = I->second;
- if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, ME, Pred, state,
+ if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, msg, Pred, state,
tag)) {
evaluated = true;
break;
@@ -2263,7 +2302,7 @@ void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME,
// Now that the arguments are processed, handle the previsits checks.
ExplodedNodeSet DstPrevisit;
- CheckerVisit(ME, DstPrevisit, ArgsEvaluated, PreVisitStmtCallback);
+ CheckerVisitObjCMessage(ME, DstPrevisit, ArgsEvaluated, /*isPreVisit=*/true);
// Proceed with evaluate the message expression.
ExplodedNodeSet dstEval;
@@ -2305,7 +2344,7 @@ void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME,
Builder->BuildSinks = true;
// Dispatch to plug-in transfer function.
- evalObjCMessageExpr(dstEval, ME, Pred, notNilState);
+ evalObjCMessage(dstEval, ME, Pred, notNilState);
}
else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) {
IdentifierInfo* ClsName = Iface->getIdentifier();
@@ -2353,7 +2392,7 @@ void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME,
Builder->BuildSinks = true;
// Dispatch to plug-in transfer function.
- evalObjCMessageExpr(dstEval, ME, Pred, Builder->GetState(Pred));
+ evalObjCMessage(dstEval, ME, Pred, Builder->GetState(Pred));
}
// Handle the case where no nodes where generated. Auto-generate that
@@ -2365,7 +2404,7 @@ void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME,
// Finally, perform the post-condition check of the ObjCMessageExpr and store
// the created nodes in 'Dst'.
- CheckerVisit(ME, Dst, dstEval, PostVisitStmtCallback);
+ CheckerVisitObjCMessage(ME, Dst, dstEval, /*isPreVisit=*/false);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index 6ef242ba42..b1b4773aee 100644
--- a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
@@ -39,7 +39,7 @@ public:
return &x;
}
- void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+ void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
};
} // end anonymous namespace
@@ -54,10 +54,10 @@ void ento::RegisterNSAutoreleasePoolChecks(ExprEngine &Eng) {
}
void
-NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
- const ObjCMessageExpr *ME) {
+NSAutoreleasePoolChecker::preVisitObjCMessage(CheckerContext &C,
+ ObjCMessage msg) {
- const Expr *receiver = ME->getInstanceReceiver();
+ const Expr *receiver = msg.getInstanceReceiver();
if (!receiver)
return;
@@ -75,13 +75,13 @@ NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
return;
// Sending 'release' message?
- if (ME->getSelector() != releaseS)
+ if (msg.getSelector() != releaseS)
return;
- SourceRange R = ME->getSourceRange();
+ SourceRange R = msg.getSourceRange();
C.getBugReporter().EmitBasicReport("Use -drain instead of -release",
"API Upgrade (Apple)",
"Use -drain instead of -release when using NSAutoreleasePool "
- "and garbage collection", ME->getLocStart(), &R, 1);
+ "and garbage collection", R.getBegin(), &R, 1);
}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index 9eb6b19ec7..c887ac86ef 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -58,7 +58,7 @@ using namespace ento;
static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND);
static bool isInitializationMethod(const ObjCMethodDecl *MD);
-static bool isInitMessage(const ObjCMessageExpr *E);
+static bool isInitMessage(const ObjCMessage &msg);
static bool isSelfVar(SVal location, CheckerContext &C);
namespace {
@@ -82,7 +82,7 @@ class ObjCSelfInitChecker : public CheckerVisitor<ObjCSelfInitChecker> {
public:
static void *getTag() { static int tag = 0; return &tag; }
- void PostVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *E);
+ void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
void PostVisitObjCIvarRefExpr(CheckerContext &C, const ObjCIvarRefExpr *E);
void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
void PreVisitGenericCall(CheckerContext &C, const CallExpr *CE);
@@ -176,8 +176,8 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C,
C.EmitReport(report);
}
-void ObjCSelfInitChecker::PostVisitObjCMessageExpr(CheckerContext &C,
- const ObjCMessageExpr *E) {
+void ObjCSelfInitChecker::postVisitObjCMessage(CheckerContext &C,
+ ObjCMessage msg) {
// When encountering a message that does initialization (init rule),
// tag the return value so that we know later on that if self has this value
// then it is properly initialized.
@@ -187,10 +187,10 @@ void ObjCSelfInitChecker::PostVisitObjCMessageExpr(CheckerContext &C,
C.getCurrentAnalysisContext()->getDecl())))
return;
- if (isInitMessage(E)) {
+ if (isInitMessage(msg)) {
// Tag the return value as the result of an initializer.
const GRState *state = C.getState();
- SVal V = state->getSVal(E);
+ SVal V = state->getSVal(msg.getOriginExpr());
addSelfFlag(V, SelfFlag_InitRes, C);
return;
}
@@ -301,6 +301,6 @@ static bool isInitializationMethod(const ObjCMethodDecl *MD) {
/*ignorePrefix=*/false) == cocoa::InitRule;
}
-static bool isInitMessage(const ObjCMessageExpr *E) {
- return cocoa::deriveNamingConvention(E->getSelector()) == cocoa::InitRule;
+static bool isInitMessage(const ObjCMessage &msg) {
+ return cocoa::deriveNamingConvention(msg.getSelector()) == cocoa::InitRule;
}
diff --git a/lib/StaticAnalyzer/ObjCMessage.cpp b/lib/StaticAnalyzer/ObjCMessage.cpp
new file mode 100644
index 0000000000..53c7175013
--- /dev/null
+++ b/lib/StaticAnalyzer/ObjCMessage.cpp
@@ -0,0 +1,99 @@
+//===- ObjCMessage.cpp - Wrapper for ObjC messages and dot syntax -*- C++ -*--//
+//
+// The LLVM Compiler Infrastruct