aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer')
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp25
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp34
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineObjC.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/ObjCMessage.cpp93
6 files changed, 50 insertions, 112 deletions
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 88a3be4139..3a4c15f0d2 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -32,6 +32,7 @@ class CallAndMessageChecker
mutable OwningPtr<BugType> BT_call_undef;
mutable OwningPtr<BugType> BT_call_arg;
mutable OwningPtr<BugType> BT_msg_undef;
+ mutable OwningPtr<BugType> BT_objc_prop_undef;
mutable OwningPtr<BugType> BT_msg_arg;
mutable OwningPtr<BugType> BT_msg_ret;
public:
@@ -228,11 +229,21 @@ void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
SVal recVal = state->getSVal(receiver, LCtx);
if (recVal.isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
- if (!BT_msg_undef)
- BT_msg_undef.reset(new BuiltinBug("Receiver in message expression is "
- "an uninitialized value"));
+ BugType *BT = 0;
+ if (msg.isPureMessageExpr()) {
+ if (!BT_msg_undef)
+ BT_msg_undef.reset(new BuiltinBug("Receiver in message expression "
+ "is an uninitialized value"));
+ BT = BT_msg_undef.get();
+ }
+ else {
+ if (!BT_objc_prop_undef)
+ BT_objc_prop_undef.reset(new BuiltinBug("Property access on an "
+ "uninitialized object pointer"));
+ BT = BT_objc_prop_undef.get();
+ }
BugReport *R =
- new BugReport(*BT_msg_undef, BT_msg_undef->getName(), N);
+ new BugReport(*BT, BT->getName(), N);
R->addRange(receiver->getSourceRange());
R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
receiver));
@@ -306,13 +317,13 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
if (CanRetTy->isStructureOrClassType()) {
// Structure returns are safe since the compiler zeroes them out.
SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
- C.addTransition(state->BindExpr(msg.getOriginExpr(), LCtx, V));
+ C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
return;
}
// Other cases: check if sizeof(return type) > sizeof(void*)
if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
- .isConsumedExpr(msg.getOriginExpr())) {
+ .isConsumedExpr(msg.getMessageExpr())) {
// Compute: sizeof(void *) and sizeof(return type)
const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
@@ -343,7 +354,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
// of this case unless we have *a lot* more knowledge.
//
SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
- C.addTransition(state->BindExpr(msg.getOriginExpr(), LCtx, V));
+ C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index dbbab4891c..165dff5b10 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -196,7 +196,7 @@ void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg,
// value out when we return from this method.
state = state->set<CalledInit>(true);
- SVal V = state->getSVal(msg.getOriginExpr(), C.getLocationContext());
+ SVal V = state->getSVal(msg.getMessageExpr(), C.getLocationContext());
addSelfFlag(state, V, SelfFlag_InitRes, C);
return;
}
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index cb4da7cf4c..6f7a47fb8f 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -190,8 +190,10 @@ namespace {
NodeBuilder &Bldr, ExplodedNode *Pred) {
ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind :
ProgramPoint::PostStmtKind;
- const ProgramPoint &L = ProgramPoint::getProgramPoint(Msg.getOriginExpr(),
- K, Pred->getLocationContext(), checkFn.Checker);
+ const ProgramPoint &L =
+ ProgramPoint::getProgramPoint(Msg.getMessageExpr(),
+ K, Pred->getLocationContext(),
+ checkFn.Checker);
CheckerContext C(Bldr, Eng, Pred, L);
checkFn(Msg, C);
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 6f588c5ae1..34ad23a429 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -808,11 +808,33 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Bldr.addNodes(Dst);
break;
- case Stmt::ObjCMessageExprClass:
+ case Stmt::ObjCMessageExprClass: {
Bldr.takeNodes(Pred);
- VisitObjCMessage(cast<ObjCMessageExpr>(S), Pred, Dst);
+ // Is this a property access?
+ const ParentMap &PM = Pred->getLocationContext()->getParentMap();
+ const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(S);
+ bool evaluated = false;
+
+ if (const PseudoObjectExpr *PO =
+ dyn_cast_or_null<PseudoObjectExpr>(PM.getParent(S))) {
+ const Expr *syntactic = PO->getSyntacticForm();
+ if (const ObjCPropertyRefExpr *PR =
+ dyn_cast<ObjCPropertyRefExpr>(syntactic)) {
+ bool isSetter = ME->getNumArgs() > 0;
+ VisitObjCMessage(ObjCMessage(ME, PR, isSetter), Pred, Dst);
+ evaluated = true;
+ }
+ else if (isa<BinaryOperator>(syntactic)) {
+ VisitObjCMessage(ObjCMessage(ME, 0, true), Pred, Dst);
+ }
+ }
+
+ if (!evaluated)
+ VisitObjCMessage(ME, Pred, Dst);
+
Bldr.addNodes(Dst);
break;
+ }
case Stmt::ObjCAtThrowStmtClass: {
// FIXME: This is not complete. We basically treat @throw as
@@ -1439,9 +1461,7 @@ void ExprEngine::evalStore(ExplodedNodeSet &Dst, const Expr *AssignE,
const Expr *StoreE = AssignE ? AssignE : LocationE;
if (isa<loc::ObjCPropRef>(location)) {
- loc::ObjCPropRef prop = cast<loc::ObjCPropRef>(location);
- return VisitObjCMessage(ObjCPropertySetter(prop.getPropRefExpr(),
- StoreE, Val), Pred, Dst);
+ assert(false);
}
// Evaluate the location (checks for bad dereferences).
@@ -1466,9 +1486,7 @@ void ExprEngine::evalLoad(ExplodedNodeSet &Dst, const Expr *Ex,
assert(!isa<NonLoc>(location) && "location cannot be a NonLoc.");
if (isa<loc::ObjCPropRef>(location)) {
- loc::ObjCPropRef prop = cast<loc::ObjCPropRef>(location);
- return VisitObjCMessage(ObjCPropertyGetter(prop.getPropRefExpr(), Ex),
- Pred, Dst);
+ assert(false);
}
// Are we loading from a region? This actually results in two loads; one
diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index b5ceb64fab..72d03a1585 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -267,7 +267,7 @@ void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
state = invalidateArguments(state, CallOrObjCMessage(msg, state, LCtx), LCtx);
// And create the new node.
- Bldr.generateNode(msg.getOriginExpr(), Pred, state, GenSink);
+ Bldr.generateNode(msg.getMessageExpr(), Pred, state, GenSink);
assert(Bldr.hasGeneratedNodes());
}
diff --git a/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
index ac571a5ef6..65cdcd9d99 100644
--- a/lib/StaticAnalyzer/Core/ObjCMessage.cpp
+++ b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
@@ -18,104 +18,11 @@
using namespace clang;
using namespace ento;
-QualType ObjCMessage::getType(ASTContext &ctx) const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getType();
- const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
- if (isPropertySetter())
- return ctx.VoidTy;
- return propE->getType();
-}
-
-Selector ObjCMessage::getSelector() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getSelector();
- const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
- if (isPropertySetter())
- return propE->getSetterSelector();
- return propE->getGetterSelector();
-}
-
-ObjCMethodFamily ObjCMessage::getMethodFamily() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- // Case 1. Explicit message send.
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getMethodFamily();
-
- const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
-
- // Case 2. Reference to implicit property.
- if (propE->isImplicitProperty()) {
- if (isPropertySetter())
- return propE->getImplicitPropertySetter()->getMethodFamily();
- else
- return propE->getImplicitPropertyGetter()->getMethodFamily();
- }
-
- // Case 3. Reference to explicit property.
- const ObjCPropertyDecl *prop = propE->getExplicitProperty();
- if (isPropertySetter()) {
- if (prop->getSetterMethodDecl())
- return prop->getSetterMethodDecl()->getMethodFamily();
- return prop->getSetterName().getMethodFamily();
- } else {
- if (prop->getGetterMethodDecl())
- return prop->getGetterMethodDecl()->getMethodFamily();
- return prop->getGetterName().getMethodFamily();
- }
-}
-
-const ObjCMethodDecl *ObjCMessage::getMethodDecl() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getMethodDecl();
- const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
- if (propE->isImplicitProperty())
- return isPropertySetter() ? propE->getImplicitPropertySetter()
- : propE->getImplicitPropertyGetter();
- return 0;
-}
-
-const ObjCInterfaceDecl *ObjCMessage::getReceiverInterface() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getReceiverInterface();
- const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
- if (propE->isClassReceiver())
- return propE->getClassReceiver();
- QualType recT;
- if (const Expr *recE = getInstanceReceiver())
- recT = recE->getType();
- else {
- assert(propE->isSuperReceiver());
- recT = propE->getSuperReceiverType();
- }
- if (const ObjCObjectPointerType *Ptr = recT->getAs<ObjCObjectPointerType>())
- return Ptr->getInterfaceDecl();
- return 0;
-}
-
-const Expr *ObjCMessage::getArgExpr(unsigned i) const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- assert(i < getNumArgs() && "Invalid index for argument");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getArg(i);
- assert(isPropertySetter());
- if (const BinaryOperator *bop = dyn_cast<BinaryOperator>(OriginE))
- if (bop->isAssignmentOp())
- return bop->getRHS();
- return 0;
-}
-
QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const {
QualType resultTy;
bool isLVal = false;
if (isObjCMessage()) {
- isLVal = isa<ObjCMessageExpr>(Msg.getOriginExpr()) &&
- Msg.getOriginExpr()->isLValue();
resultTy = Msg.getResultType(ctx);
} else if (const CXXConstructExpr *Ctor =
CallE.dyn_cast<const CXXConstructExpr *>()) {