bool IntegerOverflowChecker::hasGlobalVariablesOrMembers(const Stmt *S, CheckerContext &C) const { if (S == NULL || S->getStmtClass() == Stmt::IntegerLiteralClass) return false; ProgramStateRef State = C.getState(); const LocationContext *LCtx = C.getLocationContext(); if ((S->getStmtClass() != Stmt::ImplicitCastExprClass) && isInWhiteList(S, State, LCtx)) return true; if (const MemberExpr *MExpr = dyn_cast<MemberExpr>(S)) { if (MExpr->getMemberDecl()->isFunctionOrFunctionTemplate()) return hasGlobalVariablesOrMembers(MExpr->getMemberDecl()->getBody(), C); // We found member usage! return true; } if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) if (isa<DeclRefExpr>(ICE->getSubExpr()) && isInWhiteList(C.getSVal(ICE), State)) return true; if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) if (const VarDecl *VarD = dyn_cast<VarDecl>(DRE->getDecl())) { Loc VLoc = C.getStoreManager().getLValueVar(VarD, LCtx); SVal VVal = C.getStoreManager().getBinding(State->getStore(), VLoc); if (isInWhiteList(VVal, State)) return true; } // We will not surrender! for (auto I = S->child_begin(); I != S->child_end(); I++) if (hasGlobalVariablesOrMembers(*I, C)) return true; return false; }
void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, ExplodedNode *Pred, ExplodedNodeSet &Dst) { StmtNodeBuilder B(Pred, Dst, *currBldrCtx); const InitListExpr *ILE = cast<InitListExpr>(CL->getInitializer()->IgnoreParens()); ProgramStateRef state = Pred->getState(); SVal ILV = state->getSVal(ILE, Pred->getLocationContext()); const LocationContext *LC = Pred->getLocationContext(); state = state->bindCompoundLiteral(CL, LC, ILV); // Compound literal expressions are a GNU extension in C++. // Unlike in C, where CLs are lvalues, in C++ CLs are prvalues, // and like temporary objects created by the functional notation T() // CLs are destroyed at the end of the containing full-expression. // HOWEVER, an rvalue of array type is not something the analyzer can // reason about, since we expect all regions to be wrapped in Locs. // So we treat array CLs as lvalues as well, knowing that they will decay // to pointers as soon as they are used. if (CL->isGLValue() || CL->getType()->isArrayType()) B.generateNode(CL, Pred, state->BindExpr(CL, LC, state->getLValue(CL, LC))); else B.generateNode(CL, Pred, state->BindExpr(CL, LC, ILV)); }
void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const { ProgramStateRef State = C.getState(); // Check if this is the branch for the end of the loop. SVal CollectionSentinel = State->getSVal(FCS, C.getLocationContext()); if (CollectionSentinel.isZeroConstant()) return; // See if the collection is one where we /know/ the elements are non-nil. const Expr *Collection = FCS->getCollection(); if (!isKnownNonNilCollectionType(Collection->getType())) return; // FIXME: Copied from ExprEngineObjC. const Stmt *Element = FCS->getElement(); SVal ElementVar; if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) { const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl()); assert(ElemDecl->getInit() == 0); ElementVar = State->getLValue(ElemDecl, C.getLocationContext()); } else { ElementVar = State->getSVal(Element, C.getLocationContext()); } if (!ElementVar.getAs<Loc>()) return; // Go ahead and assume the value is non-nil. SVal Val = State->getSVal(ElementVar.castAs<Loc>()); State = State->assume(Val.castAs<DefinedOrUnknownSVal>(), true); C.addTransition(State); }
void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const { ProgramStateRef State = C.getState(); AllocatedDataTy ASet = State->get<AllocatedData>(); if (ASet.isEmpty()) return; bool Changed = false; AllocationPairVec Errors; for (AllocatedDataTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) { if (SR.isLive(I->first)) continue; Changed = true; State = State->remove<AllocatedData>(I->first); // If the allocated symbol is null or if the allocation call might have // returned an error, do not report. ConstraintManager &CMgr = State->getConstraintManager(); ConditionTruthVal AllocFailed = CMgr.isNull(State, I.getKey()); if (AllocFailed.isConstrainedTrue() || definitelyReturnedError(I->second.Region, State, C.getSValBuilder())) continue; Errors.push_back(std::make_pair(I->first, &I->second)); } if (!Changed) { // Generate the new, cleaned up state. C.addTransition(State); return; } static CheckerProgramPointTag Tag(this, "DeadSymbolsLeak"); ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag); // Generate the error reports. for (const auto P : Errors) C.emitReport(generateAllocatedDataNotReleasedReport(P, N, C)); // Generate the new, cleaned up state. C.addTransition(State, N); }
bool GenericTaintChecker::propagateFromPre(const CallExpr *CE, CheckerContext &C) const { ProgramStateRef State = C.getState(); // Depending on what was tainted at pre-visit, we determined a set of // arguments which should be tainted after the function returns. These are // stored in the state as TaintArgsOnPostVisit set. TaintArgsOnPostVisitTy TaintArgs = State->get<TaintArgsOnPostVisit>(); if (TaintArgs.isEmpty()) return false; for (llvm::ImmutableSet<unsigned>::iterator I = TaintArgs.begin(), E = TaintArgs.end(); I != E; ++I) { unsigned ArgNum = *I; // Special handling for the tainted return value. if (ArgNum == ReturnValueIndex) { State = State->addTaint(CE, C.getLocationContext()); continue; } // The arguments are pointer arguments. The data they are pointing at is // tainted after the call. if (CE->getNumArgs() < (ArgNum + 1)) return false; const Expr* Arg = CE->getArg(ArgNum); Optional<SVal> V = getPointedToSVal(C, Arg); if (V) State = State->addTaint(*V); } // Clear up the taint info from the state. State = State->remove<TaintArgsOnPostVisit>(); if (State != C.getState()) { C.addTransition(State); return true; } return false; }
PathDiagnosticPiece *DivisionBRVisitor::VisitNode(const ExplodedNode *Succ, const ExplodedNode *Pred, BugReporterContext &BRC, BugReport &BR) { if (Satisfied) return nullptr; const Expr *E = nullptr; if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>()) if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) { BinaryOperator::Opcode Op = BO->getOpcode(); if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign || Op == BO_RemAssign) { E = BO->getRHS(); } } if (!E) return nullptr; ProgramStateRef State = Succ->getState(); SVal S = State->getSVal(E, Succ->getLocationContext()); if (ZeroSymbol == S.getAsSymbol() && SFC == Succ->getStackFrame()) { Satisfied = true; // Construct a new PathDiagnosticPiece. ProgramPoint P = Succ->getLocation(); PathDiagnosticLocation L = PathDiagnosticLocation::create(P, BRC.getSourceManager()); if (!L.isValid() || !L.asLocation().isValid()) return nullptr; return new PathDiagnosticEventPiece( L, "Division with compared value made here"); } return nullptr; }
ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, ProgramStateRef Orig) const { ProgramStateRef Result = (Orig ? Orig : getState()); // Don't invalidate anything if the callee is marked pure/const. if (const Decl *callee = getDecl()) if (callee->hasAttr<PureAttr>() || callee->hasAttr<ConstAttr>()) return Result; SmallVector<SVal, 8> ValuesToInvalidate; RegionAndSymbolInvalidationTraits ETraits; getExtraInvalidatedValues(ValuesToInvalidate, &ETraits); // Indexes of arguments whose values will be preserved by the call. llvm::SmallSet<unsigned, 4> PreserveArgs; if (!argumentsMayEscape()) findPtrToConstParams(PreserveArgs, *this); for (unsigned Idx = 0, Count = getNumArgs(); Idx != Count; ++Idx) { // Mark this region for invalidation. We batch invalidate regions // below for efficiency. if (PreserveArgs.count(Idx)) if (const MemRegion *MR = getArgSVal(Idx).getAsRegion()) ETraits.setTrait(MR->StripCasts(), RegionAndSymbolInvalidationTraits::TK_PreserveContents); // TODO: Factor this out + handle the lower level const pointers. ValuesToInvalidate.push_back(getArgSVal(Idx)); } // Invalidate designated regions using the batch invalidation API. // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate // global variables. return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(), BlockCount, getLocationContext(), /*CausedByPointerEscape*/ true, /*Symbols=*/nullptr, this, &ETraits); }
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; } } }
void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const { // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker. // They can possibly be refactored. if (CE->getNumArgs() < 1) return; // Check if the first argument is stack allocated. If so, issue a warning // because that's likely to be bad news. ProgramStateRef state = C.getState(); const MemRegion *R = state->getSVal(CE->getArg(0), C.getLocationContext()).getAsRegion(); if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) return; ExplodedNode *N = C.generateSink(state); if (!N) return; SmallString<256> S; llvm::raw_svector_ostream os(S); os << "Call to 'pthread_once' uses"; if (const VarRegion *VR = dyn_cast<VarRegion>(R)) os << " the local variable '" << VR->getDecl()->getName() << '\''; else os << " stack allocated memory"; os << " for the \"control\" value. Using such transient memory for " "the control value is potentially dangerous."; if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) os << " Perhaps you intended to declare the variable as 'static'?"; LazyInitialize(BT_pthreadOnce, "Improper use of 'pthread_once'"); auto report = llvm::make_unique<BugReport>(*BT_pthreadOnce, os.str(), N); report->addRange(CE->getArg(0)->getSourceRange()); C.emitReport(std::move(report)); }
void PointerSubChecker::checkPreStmt(const BinaryOperator *B, CheckerContext &C) const { // When doing pointer subtraction, if the two pointers do not point to the // same memory chunk, emit a warning. if (B->getOpcode() != BO_Sub) return; ProgramStateRef state = C.getState(); const LocationContext *LCtx = C.getLocationContext(); SVal LV = state->getSVal(B->getLHS(), LCtx); SVal RV = state->getSVal(B->getRHS(), LCtx); const MemRegion *LR = LV.getAsRegion(); const MemRegion *RR = RV.getAsRegion(); if (!(LR && RR)) return; const MemRegion *BaseLR = LR->getBaseRegion(); const MemRegion *BaseRR = RR->getBaseRegion(); if (BaseLR == BaseRR) return; // Allow arithmetic on different symbolic regions. if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR)) return; if (ExplodedNode *N = C.addTransition()) { if (!BT) BT.reset( new BuiltinBug(this, "Pointer subtraction", "Subtraction of two pointers that do not point to " "the same memory chunk may cause incorrect result.")); auto R = llvm::make_unique<BugReport>(*BT, BT->getDescription(), N); R->addRange(B->getSourceRange()); C.emitReport(std::move(R)); } }
/// Returns the released value if M is a call a setter that releases /// and nils out its underlying instance variable. SymbolRef ObjCDeallocChecker::getValueReleasedByNillingOut(const ObjCMethodCall &M, CheckerContext &C) const { SVal ReceiverVal = M.getReceiverSVal(); if (!ReceiverVal.isValid()) return nullptr; if (M.getNumArgs() == 0) return nullptr; if (!M.getArgExpr(0)->getType()->isObjCRetainableType()) return nullptr; // Is the first argument nil? SVal Arg = M.getArgSVal(0); ProgramStateRef notNilState, nilState; std::tie(notNilState, nilState) = M.getState()->assume(Arg.castAs<DefinedOrUnknownSVal>()); if (!(nilState && !notNilState)) return nullptr; const ObjCPropertyDecl *Prop = M.getAccessedProperty(); if (!Prop) return nullptr; ObjCIvarDecl *PropIvarDecl = Prop->getPropertyIvarDecl(); if (!PropIvarDecl) return nullptr; ProgramStateRef State = C.getState(); SVal LVal = State->getLValue(PropIvarDecl, ReceiverVal); Optional<Loc> LValLoc = LVal.getAs<Loc>(); if (!LValLoc) return nullptr; SVal CurrentValInIvar = State->getSVal(LValLoc.getValue()); return CurrentValInIvar.getAsSymbol(); }
void InnerPointerChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { ProgramStateRef State = C.getState(); if (const auto *ICall = dyn_cast<CXXInstanceCall>(&Call)) { // TODO: Do we need these to be typed? const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>( ICall->getCXXThisVal().getAsRegion()); if (!ObjRegion) return; if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) { SVal RawPtr = Call.getReturnValue(); if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) { // Start tracking this raw pointer by adding it to the set of symbols // associated with this container object in the program state map. PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>(); const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion); PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet(); assert(C.wasInlined || !Set.contains(Sym)); Set = F.add(Set, Sym); State = State->set<RawPtrMap>(ObjRegion, Set); C.addTransition(State); } return; } // Check [string.require] / second point. if (isInvalidatingMemberFunction(Call)) { markPtrSymbolsReleased(Call, State, ObjRegion, C); return; } } // Check [string.require] / first point. checkFunctionArguments(Call, State, C); }
static StringRef getCalleeName(ProgramStateRef State, const CallExpr *CE, const LocationContext *LCtx) { const Expr *Callee = CE->getCallee(); SVal L = State->getSVal(Callee, LCtx); const FunctionDecl *funDecl = L.getAsFunctionDecl(); if (!funDecl) return StringRef(); IdentifierInfo *funI = funDecl->getIdentifier(); if (!funI) return StringRef(); return funI->getName(); }
void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { CanQualType T = getContext().getCanonicalType(BE->getType()); // Get the value of the block itself. SVal V = svalBuilder.getBlockPointer(BE->getBlockDecl(), T, Pred->getLocationContext(), currBldrCtx->blockCount()); ProgramStateRef State = Pred->getState(); // If we created a new MemRegion for the block, we should explicitly bind // the captured variables. if (const BlockDataRegion *BDR = dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) { BlockDataRegion::referenced_vars_iterator I = BDR->referenced_vars_begin(), E = BDR->referenced_vars_end(); for (; I != E; ++I) { const MemRegion *capturedR = I.getCapturedRegion(); const MemRegion *originalR = I.getOriginalRegion(); if (capturedR != originalR) { SVal originalV = State->getSVal(loc::MemRegionVal(originalR)); State = State->bindLoc(loc::MemRegionVal(capturedR), originalV); } } } ExplodedNodeSet Tmp; StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx); Bldr.generateNode(BE, Pred, State->BindExpr(BE, Pred->getLocationContext(), V), nullptr, ProgramPoint::PostLValueKind); // FIXME: Move all post/pre visits to ::Visit(). getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this); }
ProgramStateRef BasicConstraintManager::AddNE(ProgramStateRef state, SymbolRef sym, const llvm::APSInt& V) { // First, retrieve the NE-set associated with the given symbol. ConstNotEqTy::data_type* T = state->get<ConstNotEq>(sym); ProgramState::IntSetTy S = T ? *T : ISetFactory.getEmptySet(); // Now add V to the NE set. S = ISetFactory.add(S, &state->getBasicVals().getValue(V)); // Create a new state with the old binding replaced. return state->set<ConstNotEq>(sym, S); }
void CallAndMessageChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const{ const Expr *Callee = CE->getCallee()->IgnoreParens(); ProgramStateRef State = C.getState(); const LocationContext *LCtx = C.getLocationContext(); SVal L = State->getSVal(Callee, LCtx); if (L.isUndef()) { if (!BT_call_undef) BT_call_undef.reset(new BuiltinBug("Called function pointer is an " "uninitalized pointer value")); EmitBadCall(BT_call_undef.get(), C, CE); return; } if (L.isZeroConstant()) { if (!BT_call_null) BT_call_null.reset( new BuiltinBug("Called function pointer is null (null dereference)")); EmitBadCall(BT_call_null.get(), C, CE); } }
void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { const LocationContext *LocCtxt = Pred->getLocationContext(); // Get the region of the lambda itself. const MemRegion *R = svalBuilder.getRegionManager().getCXXTempObjectRegion( LE, LocCtxt); SVal V = loc::MemRegionVal(R); ProgramStateRef State = Pred->getState(); // If we created a new MemRegion for the lambda, we should explicitly bind // the captures. CXXRecordDecl::field_iterator CurField = LE->getLambdaClass()->field_begin(); for (LambdaExpr::const_capture_init_iterator i = LE->capture_init_begin(), e = LE->capture_init_end(); i != e; ++i, ++CurField) { FieldDecl *FieldForCapture = *CurField; SVal FieldLoc = State->getLValue(FieldForCapture, V); SVal InitVal; if (!FieldForCapture->hasCapturedVLAType()) { Expr *InitExpr = *i; assert(InitExpr && "Capture missing initialization expression"); InitVal = State->getSVal(InitExpr, LocCtxt); } else { // The field stores the length of a captured variable-length array. // These captures don't have initialization expressions; instead we // get the length from the VLAType size expression. Expr *SizeExpr = FieldForCapture->getCapturedVLAType()->getSizeExpr(); InitVal = State->getSVal(SizeExpr, LocCtxt); } State = State->bindLoc(FieldLoc, InitVal); } // Decay the Loc into an RValue, because there might be a // MaterializeTemporaryExpr node above this one which expects the bound value // to be an RValue. SVal LambdaRVal = State->getSVal(R); ExplodedNodeSet Tmp; StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx); // FIXME: is this the right program point kind? Bldr.generateNode(LE, Pred, State->BindExpr(LE, LocCtxt, LambdaRVal), nullptr, ProgramPoint::PostLValueKind); // FIXME: Move all post/pre visits to ::Visit(). getCheckerManager().runCheckersForPostStmt(Dst, Tmp, LE, *this); }
// Need to handle DeclStmts to pick up initializing of iterators and to mark // uninitialized ones as Undefined. void IteratorsChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { const Decl *D = *DS->decl_begin(); const VarDecl *VD = dyn_cast<VarDecl>(D); // Only care about iterators. if (getTemplateKind(VD->getType()) != VectorIteratorKind) return; // Get the MemRegion associated with the iterator and mark it as Undefined. ProgramStateRef state = C.getState(); Loc VarLoc = state->getLValue(VD, C.getLocationContext()); const MemRegion *MR = VarLoc.getAsRegion(); if (!MR) return; state = state->set<IteratorState>(MR, RefState::getUndefined()); // if there is an initializer, handle marking Valid if a proper initializer const Expr *InitEx = VD->getInit(); if (InitEx) { // FIXME: This is too syntactic. Since 'InitEx' will be analyzed first // it should resolve to an SVal that we can check for validity // *semantically* instead of walking through the AST. if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(InitEx)) { if (CE->getNumArgs() == 1) { const Expr *E = CE->getArg(0); if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E)) E = M->GetTemporaryExpr(); if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) InitEx = ICE->getSubExpr(); state = handleAssign(state, MR, InitEx, C.getLocationContext()); } } } C.addTransition(state); }
void InnerPointerChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState(); PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>(); RawPtrMapTy RPM = State->get<RawPtrMap>(); for (const auto Entry : RPM) { if (!SymReaper.isLiveRegion(Entry.first)) { // Due to incomplete destructor support, some dead regions might // remain in the program state map. Clean them up. State = State->remove<RawPtrMap>(Entry.first); } if (const PtrSet *OldSet = State->get<RawPtrMap>(Entry.first)) { PtrSet CleanedUpSet = *OldSet; for (const auto Symbol : Entry.second) { if (!SymReaper.isLive(Symbol)) CleanedUpSet = F.remove(CleanedUpSet, Symbol); } State = CleanedUpSet.isEmpty() ? State->remove<RawPtrMap>(Entry.first) : State->set<RawPtrMap>(Entry.first, CleanedUpSet); } } C.addTransition(State); }
void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, ExplodedNode *Pred, ExplodedNodeSet &Dst) { StmtNodeBuilder B(Pred, Dst, *currBldrCtx); ProgramStateRef State = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); const Expr *Init = CL->getInitializer(); SVal V = State->getSVal(CL->getInitializer(), LCtx); if (isa<CXXConstructExpr>(Init)) { // No work needed. Just pass the value up to this expression. } else { assert(isa<InitListExpr>(Init)); Loc CLLoc = State->getLValue(CL, LCtx); State = State->bindLoc(CLLoc, V, LCtx); if (CL->isGLValue()) V = CLLoc; } B.generateNode(CL, Pred, State->BindExpr(CL, LCtx, V)); }
ProgramStateRef ExprEngine::handleLVectorSplat( ProgramStateRef state, const LocationContext* LCtx, const CastExpr* CastE, StmtNodeBuilder &Bldr, ExplodedNode* Pred) { // Recover some path sensitivity by conjuring a new value. QualType resultType = CastE->getType(); if (CastE->isGLValue()) resultType = getContext().getPointerType(resultType); SVal result = svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType, currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, result); Bldr.generateNode(CastE, Pred, state); return state; }
Optional<SVal> GenericTaintChecker::getPointedToSVal(CheckerContext &C, const Expr *Arg) { ProgramStateRef State = C.getState(); SVal AddrVal = C.getSVal(Arg->IgnoreParens()); if (AddrVal.isUnknownOrUndef()) return None; Optional<Loc> AddrLoc = AddrVal.getAs<Loc>(); if (!AddrLoc) return None; QualType ArgTy = Arg->getType().getCanonicalType(); if (!ArgTy->isPointerType()) return None; QualType ValTy = ArgTy->getPointeeType(); // Do not dereference void pointers. Treat them as byte pointers instead. // FIXME: we might want to consider more than just the first byte. if (ValTy->isVoidType()) ValTy = C.getASTContext().CharTy; return State->getSVal(*AddrLoc, ValTy); }
void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad, const Stmt *S, CheckerContext &C) const { if (!isLoad) return; if (loc.isUndef() || !loc.getAs<Loc>()) return; ASTContext &Ctx = C.getASTContext(); ProgramStateRef state = C.getState(); // If we are loading from NSError**/CFErrorRef* parameter, mark the resulting // SVal so that we can later check it when handling the // ImplicitNullDerefEvent event. // FIXME: Cumbersome! Maybe add hook at construction of SVals at start of // function ? QualType parmT = parameterTypeFromSVal(loc, C); if (parmT.isNull()) return; if (!NSErrorII) NSErrorII = &Ctx.Idents.get("NSError"); if (!CFErrorII) CFErrorII = &Ctx.Idents.get("CFErrorRef"); if (ShouldCheckNSError && IsNSError(parmT, NSErrorII)) { setFlag<NSErrorOut>(state, state->getSVal(loc.castAs<Loc>()), C); return; } if (ShouldCheckCFError && IsCFError(parmT, CFErrorII)) { setFlag<CFErrorOut>(state, state->getSVal(loc.castAs<Loc>()), C); return; } }
ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, const LocationContext *LCtx, ProgramStateRef State) { const Expr *E = Call.getOriginExpr(); if (!E) return State; // Some method families have known return values. if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) { switch (Msg->getMethodFamily()) { default: break; case OMF_autorelease: case OMF_retain: case OMF_self: { // These methods return their receivers. return State->BindExpr(E, LCtx, Msg->getReceiverSVal()); } } } else if (const CXXConstructorCall *C = dyn_cast<CXXConstructorCall>(&Call)){ SVal ThisV = C->getCXXThisVal(); // If the constructed object is a temporary prvalue, get its bindings. if (isTemporaryPRValue(cast<CXXConstructExpr>(E), ThisV)) ThisV = State->getSVal(ThisV.castAs<Loc>()); return State->BindExpr(E, LCtx, ThisV); } // Conjure a symbol if the return value is unknown. QualType ResultTy = Call.getResultType(); SValBuilder &SVB = getSValBuilder(); unsigned Count = currBldrCtx->blockCount(); SVal R = SVB.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count); return State->BindExpr(E, LCtx, R); }
/// Finds argument index of the out paramter in the call {@code S} /// corresponding to the symbol {@code Sym}. /// If none found, returns None. static Optional<unsigned> findArgIdxOfSymbol(ProgramStateRef CurrSt, const LocationContext *LCtx, SymbolRef &Sym, Optional<CallEventRef<>> CE) { if (!CE) return None; for (unsigned Idx = 0; Idx < (*CE)->getNumArgs(); Idx++) if (const MemRegion *MR = (*CE)->getArgSVal(Idx).getAsRegion()) if (const auto *TR = dyn_cast<TypedValueRegion>(MR)) if (CurrSt->getSVal(MR, TR->getValueType()).getAsSymExpr() == Sym) return Idx; return None; }
// When checking for error code, we need to consider the following cases: // 1) noErr / [0] // 2) someErr / [1, inf] // 3) unknown // If noError, returns true iff (1). // If !noError, returns true iff (2). bool MacOSKeychainAPIChecker::definitelyReturnedError(SymbolRef RetSym, ProgramStateRef State, SValBuilder &Builder, bool noError) const { DefinedOrUnknownSVal NoErrVal = Builder.makeIntVal(NoErr, Builder.getSymbolManager().getType(RetSym)); DefinedOrUnknownSVal NoErr = Builder.evalEQ(State, NoErrVal, nonloc::SymbolVal(RetSym)); ProgramStateRef ErrState = State->assume(NoErr, noError); if (ErrState == State) { return true; } return false; }
static bool checkParamsForPreconditionViolation(ArrayRef<ParmVarDecl *> Params, ProgramStateRef State, const LocationContext *LocCtxt) { for (const auto *ParamDecl : Params) { if (ParamDecl->isParameterPack()) break; SVal LV = State->getLValue(ParamDecl, LocCtxt); if (checkValueAtLValForInvariantViolation(State, LV, ParamDecl->getType())) { return true; } } return false; }
ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef State, DefinedSVal Cond, bool Assumption) { // If we have a Loc value, cast it to a bool NonLoc first. if (Optional<Loc> LV = Cond.getAs<Loc>()) { SValBuilder &SVB = State->getStateManager().getSValBuilder(); QualType T; const MemRegion *MR = LV->getAsRegion(); if (const TypedRegion *TR = dyn_cast_or_null<TypedRegion>(MR)) T = TR->getLocationType(); else T = SVB.getContext().VoidPtrTy; Cond = SVB.evalCast(*LV, SVB.getContext().BoolTy, T).castAs<DefinedSVal>(); } return assume(State, Cond.castAs<NonLoc>(), Assumption); }
void PthreadLockChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { ProgramStateRef state = C.getState(); const LocationContext *LCtx = C.getLocationContext(); StringRef FName = C.getCalleeName(CE); if (FName.empty()) return; if (CE->getNumArgs() != 1 && CE->getNumArgs() != 2) return; if (FName == "pthread_mutex_lock" || FName == "pthread_rwlock_rdlock" || FName == "pthread_rwlock_wrlock") AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx), false, PthreadSemantics); else if (FName == "lck_mtx_lock" || FName == "lck_rw_lock_exclusive" || FName == "lck_rw_lock_shared") AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx), false, XNUSemantics); else if (FName == "pthread_mutex_trylock" || FName == "pthread_rwlock_tryrdlock" || FName == "pthread_rwlock_trywrlock") AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx), true, PthreadSemantics); else if (FName == "lck_mtx_try_lock" || FName == "lck_rw_try_lock_exclusive" || FName == "lck_rw_try_lock_shared") AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx), true, XNUSemantics); else if (FName == "pthread_mutex_unlock" || FName == "pthread_rwlock_unlock" || FName == "lck_mtx_unlock" || FName == "lck_rw_done") ReleaseLock(C, CE, state->getSVal(CE->getArg(0), LCtx)); else if (FName == "pthread_mutex_destroy" || FName == "lck_mtx_destroy") DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx)); else if (FName == "pthread_mutex_init") InitLock(C, CE, state->getSVal(CE->getArg(0), LCtx)); }
/// Returns true when the value stored at the given location is null /// and the passed in type is nonnnull. static bool checkValueAtLValForInvariantViolation(ProgramStateRef State, SVal LV, QualType T) { if (getNullabilityAnnotation(T) != Nullability::Nonnull) return false; auto RegionVal = LV.getAs<loc::MemRegionVal>(); if (!RegionVal) return false; auto StoredVal = State->getSVal(RegionVal->getRegion()).getAs<DefinedOrUnknownSVal>(); if (!StoredVal) return false; if (getNullConstraint(*StoredVal, State) == NullConstraint::IsNull) return true; return false; }