void ObjCSelfInitChecker::checkPostStmt(const CallOrObjCMessage &CE, CheckerContext &C) const { ProgramStateRef state = C.getState(); unsigned NumArgs = CE.getNumArgs(); 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>(); const Expr *CallExpr = CE.getOriginExpr(); if (CallExpr) addSelfFlag(state, state->getSVal(CallExpr, C.getLocationContext()), prevFlags, C); return; } } }
ProgramStateRef ExprEngine::invalidateArguments(ProgramStateRef 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. SVal CalleeVal = Call.getFunctionCallee(); if (const MemRegion *Callee = CalleeVal.getAsRegion()) { if (isa<BlockDataRegion>(Callee)) RegionsToInvalidate.push_back(Callee); } } // Indexes of arguments whose values will be preserved by the call. llvm::SmallSet<unsigned, 1> PreserveArgs; findPtrToConstParams(PreserveArgs, Call); for (unsigned idx = 0, e = Call.getNumArgs(); idx != e; ++idx) { if (PreserveArgs.count(idx)) continue; 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 underlying 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 // appropriately 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. unsigned Count = currentBuilderContext->getCurrentBlockCount(); StoreManager::InvalidatedSymbols IS; // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate // global variables. return State->invalidateRegions(RegionsToInvalidate, Call.getOriginExpr(), Count, LC, &IS, &Call); }