// Try to retrieve the function declaration and find the function parameter // types which are pointers/references to a non-pointer const. // We do not invalidate the corresponding argument regions. static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs, const CallOrObjCMessage &Call) { const Decl *CallDecl = Call.getDecl(); if (!CallDecl) return; if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(CallDecl)) { const IdentifierInfo *II = FDecl->getIdentifier(); // List the cases, where the region should be invalidated even if the // argument is const. if (II) { StringRef FName = II->getName(); // - 'int pthread_setspecific(ptheread_key k, const void *)' stores a // value into thread local storage. The value can later be retrieved with // 'void *ptheread_getspecific(pthread_key)'. So even thought the // parameter is 'const void *', the region escapes through the call. // - funopen - sets a buffer for future IO calls. // - ObjC functions that end with "NoCopy" can free memory, of the passed // in buffer. // - Many CF containers allow objects to escape through custom // allocators/deallocators upon container construction. // - NSXXInsertXX, for example NSMapInsertIfAbsent, since they can // be deallocated by NSMapRemove. // - Any call that has a callback as one of the arguments. if (FName == "pthread_setspecific" || FName == "funopen" || FName.endswith("NoCopy") || (FName.startswith("NS") && (FName.find("Insert") != StringRef::npos)) || Call.isCFCGAllowingEscape(FName) || Call.hasNonZeroCallbackArg()) return; } for (unsigned Idx = 0, E = Call.getNumArgs(); Idx != E; ++Idx) { if (FDecl && Idx < FDecl->getNumParams()) { if (isPointerToConst(FDecl->getParamDecl(Idx))) PreserveArgs.insert(Idx); } } return; } if (const ObjCMethodDecl *MDecl = dyn_cast<ObjCMethodDecl>(CallDecl)) { assert(MDecl->param_size() <= Call.getNumArgs()); unsigned Idx = 0; if (Call.hasNonZeroCallbackArg()) return; for (clang::ObjCMethodDecl::param_const_iterator I = MDecl->param_begin(), E = MDecl->param_end(); I != E; ++I, ++Idx) { if (isPointerToConst(*I)) PreserveArgs.insert(Idx); } return; } }
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; } } }
void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C, CallOrObjCMessage callOrMsg, const char *BT_desc, llvm::OwningPtr<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; }
void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C, CallOrObjCMessage callOrMsg, const char *BT_desc, OwningPtr<BugType> &BT) { // Don't check for uninitialized field values in arguments if the // caller has a body that is available and we have the chance to inline it. // This is a hack, but is a reasonable compromise betweens sometimes warning // and sometimes not depending on if we decide to inline a function. const Decl *D = callOrMsg.getDecl(); const bool checkUninitFields = !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody())); for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i) if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i), callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i), checkUninitFields, BT_desc, BT)) return; }
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)) { unsigned selfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C); C.addTransition(state->set<PreCallSelfFlags>(selfFlags)); return; } else if (hasSelfFlag(argV, SelfFlag_Self, C)) { unsigned selfFlags = getSelfFlags(argV, C); C.addTransition(state->set<PreCallSelfFlags>(selfFlags)); 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); }