|
@@ -183,9 +183,6 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C,
|
|
|
|
|
|
void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg,
|
|
|
CheckerContext &C) const {
|
|
|
- CallOrObjCMessage MsgWrapper(msg, C.getState(), C.getLocationContext());
|
|
|
- checkPostStmt(MsgWrapper, C);
|
|
|
-
|
|
|
// 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.
|
|
@@ -209,6 +206,9 @@ void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ CallOrObjCMessage MsgWrapper(msg, C.getState(), C.getLocationContext());
|
|
|
+ checkPostStmt(MsgWrapper, C);
|
|
|
+
|
|
|
// We don't check for an invalid 'self' in an obj-c message expression to cut
|
|
|
// down false positives where logging functions get information from self
|
|
|
// (like its class) or doing "invalidation" on self when the initialization
|
|
@@ -277,6 +277,11 @@ void ObjCSelfInitChecker::checkPreStmt(const CallOrObjCMessage &CE,
|
|
|
CheckerContext &C) const {
|
|
|
ProgramStateRef state = C.getState();
|
|
|
unsigned NumArgs = CE.getNumArgs();
|
|
|
+ // If we passed 'self' as and argument to the call, record it in the state
|
|
|
+ // to be propagated after the call.
|
|
|
+ // Note, we could have just given up, but try to be more optimistic here and
|
|
|
+ // assume that the functions are going to continue initialization or will not
|
|
|
+ // modify self.
|
|
|
for (unsigned i = 0; i < NumArgs; ++i) {
|
|
|
SVal argV = CE.getArgSVal(i);
|
|
|
if (isSelfVar(argV, C)) {
|
|
@@ -298,14 +303,24 @@ void ObjCSelfInitChecker::checkPostStmt(const CallOrObjCMessage &CE,
|
|
|
for (unsigned i = 0; i < NumArgs; ++i) {
|
|
|
SVal argV = CE.getArgSVal(i);
|
|
|
if (isSelfVar(argV, C)) {
|
|
|
+ // If the address of 'self' is being passed to the call, assume that the
|
|
|
+ // 'self' after the call will have the same flags.
|
|
|
+ // EX: log(&self)
|
|
|
SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
|
|
|
state = state->remove<PreCallSelfFlags>();
|
|
|
addSelfFlag(state, state->getSVal(cast<Loc>(argV)), prevFlags, C);
|
|
|
return;
|
|
|
} else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
|
|
|
+ // If 'self' is passed to the call by value, assume that the function
|
|
|
+ // returns 'self'. So assign the flags, which were set on 'self' to the
|
|
|
+ // return value.
|
|
|
+ // EX: self = performMoreInitialization(self)
|
|
|
SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
|
|
|
state = state->remove<PreCallSelfFlags>();
|
|
|
- addSelfFlag(state, state->getSVal(cast<Loc>(argV)), prevFlags, C);
|
|
|
+ const Expr *CallExpr = CE.getOriginExpr();
|
|
|
+ if (CallExpr)
|
|
|
+ addSelfFlag(state, state->getSVal(CallExpr, C.getLocationContext()),
|
|
|
+ prevFlags, C);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
@@ -358,7 +373,7 @@ static bool isSelfVar(SVal location, CheckerContext &C) {
|
|
|
return false;
|
|
|
|
|
|
loc::MemRegionVal MRV = cast<loc::MemRegionVal>(location);
|
|
|
- if (const DeclRegion *DR = dyn_cast<DeclRegion>(MRV.getRegion()))
|
|
|
+ if (const DeclRegion *DR = dyn_cast<DeclRegion>(MRV.stripCasts()))
|
|
|
return (DR->getDecl() == analCtx->getSelfDecl());
|
|
|
|
|
|
return false;
|