void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const { if (!M.isInstanceMessage()) return; const ObjCInterfaceDecl *ClassID = M.getReceiverInterface(); if (!ClassID) return; FoundationClass Class = findKnownClass(ClassID); if (Class != FC_NSDictionary && Class != FC_NSArray && Class != FC_NSSet) return; SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol(); if (!ContainerS) return; // If we are processing a call to "count", get the symbolic value returned by // a call to "count" and add it to the map. if (!isCollectionCountMethod(M, C)) return; const Expr *MsgExpr = M.getOriginExpr(); SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol(); if (CountS) { ProgramStateRef State = C.getState(); C.getSymbolManager().addSymbolDependency(ContainerS, CountS); State = State->set<ContainerCountMap>(ContainerS, CountS); C.addTransition(State); } return; }
void IteratorChecker::assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal, const MemRegion *Cont) const { while (const auto *CBOR = Cont->getAs<CXXBaseObjectRegion>()) { Cont = CBOR->getSuperRegion(); } auto State = C.getState(); auto &SymMgr = C.getSymbolManager(); auto Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(), C.getASTContext().LongTy, C.blockCount()); State = setIteratorPosition(State, RetVal, IteratorPosition::getPosition(Cont, Sym)); C.addTransition(State); }
void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { ProgramStateRef State = C.getState(); const FunctionDecl *FD = C.getCalleeDecl(CE); if (!FD || FD->getKind() != Decl::Function) return; StringRef funName = C.getCalleeName(FD); // If a value has been allocated, add it to the set for tracking. unsigned idx = getTrackedFunctionIndex(funName, true); if (idx == InvalidIdx) return; const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param); // If the argument entered as an enclosing function parameter, skip it to // avoid false positives. if (isEnclosingFunctionParam(ArgExpr) && C.getLocationContext()->getParent() == 0) return; if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) { // If the argument points to something that's not a symbolic region, it // can be: // - unknown (cannot reason about it) // - undefined (already reported by other checker) // - constant (null - should not be tracked, // other constant will generate a compiler warning) // - goto (should be reported by other checker) // The call return value symbol should stay alive for as long as the // allocated value symbol, since our diagnostics depend on the value // returned by the call. Ex: Data should only be freed if noErr was // returned during allocation.) SymbolRef RetStatusSymbol = State->getSVal(CE, C.getLocationContext()).getAsSymbol(); C.getSymbolManager().addSymbolDependency(V, RetStatusSymbol); // Track the allocated value in the checker state. State = State->set<AllocatedData>(V, AllocationState(ArgExpr, idx, RetStatusSymbol)); assert(State); C.addTransition(State); } }
void IteratorChecker::handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal, const SVal &Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; while (const auto *CBOR = ContReg->getAs<CXXBaseObjectRegion>()) { ContReg = CBOR->getSuperRegion(); } // If the container already has an end symbol then use it. Otherwise first // create a new one. auto State = C.getState(); auto EndSym = getContainerEnd(State, ContReg); if (!EndSym) { auto &SymMgr = C.getSymbolManager(); EndSym = SymMgr.conjureSymbol(CE, C.getLocationContext(), C.getASTContext().LongTy, C.blockCount()); State = createContainerEnd(State, ContReg, EndSym); } State = setIteratorPosition(State, RetVal, IteratorPosition::getPosition(ContReg, EndSym)); C.addTransition(State); }