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()); 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), 0, ProgramPoint::PostLValueKind); // FIXME: Move all post/pre visits to ::Visit(). getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this); }
std::shared_ptr<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; SVal S = Succ->getSVal(E); 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 std::make_shared<PathDiagnosticEventPiece>( L, "Division with compared value made here"); } return nullptr; }
SVal ProgramState::getSVal(Loc location, QualType T) const { SVal V = getRawSVal(cast<Loc>(location), T); // If 'V' is a symbolic value that is *perfectly* constrained to // be a constant value, use that value instead to lessen the burden // on later analysis stages (so we have less symbolic values to reason // about). if (!T.isNull()) { if (SymbolRef sym = V.getAsSymbol()) { if (const llvm::APSInt *Int = getStateManager() .getConstraintManager() .getSymVal(this, sym)) { // FIXME: Because we don't correctly model (yet) sign-extension // and truncation of symbolic values, we need to convert // the integer value to the correct signedness and bitwidth. // // This shows up in the following: // // char foo(); // unsigned x = foo(); // if (x == 54) // ... // // The symbolic value stored to 'x' is actually the conjured // symbol for the call to foo(); the type of that symbol is 'char', // not unsigned. const llvm::APSInt &NewV = getBasicVals().Convert(T, *Int); if (V.getAs<Loc>()) return loc::ConcreteInt(NewV); else return nonloc::ConcreteInt(NewV); } } } return V; }
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("Pointer subtraction", "Subtraction of two pointers that do not point to " "the same memory chunk may cause incorrect result.")); BugReport *R = new BugReport(*BT, BT->getDescription(), N); R->addRange(B->getSourceRange()); C.EmitReport(R); } }
void TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const { if (ExplodedNode *N = C.generateSink(C.getState())) { if (!DivZeroBug) DivZeroBug.reset(new BuiltinBug(this, "Division by zero")); BugReport *R = new BugReport(*DivZeroBug, "Value being compared against zero has " "already been used for division", N); R->addVisitor(new DivisionBRVisitor(Val.getAsSymbol(), C.getStackFrame())); C.emitReport(R); } }
// Handle assigning to an iterator where we don't have the LValue MemRegion. const ProgramState *IteratorsChecker::handleAssign(const ProgramState *state, const Expr *lexp, const Expr *rexp, const LocationContext *LC) const { // Skip the cast if present. if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(lexp)) lexp = M->GetTemporaryExpr(); if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(lexp)) lexp = ICE->getSubExpr(); SVal sv = state->getSVal(lexp); const MemRegion *MR = sv.getAsRegion(); if (!MR) return state; RefKind kind = getTemplateKind(lexp->getType()); // If assigning to a vector, invalidate any iterators currently associated. if (kind == VectorKind) return invalidateIterators(state, MR, 0); // Make sure that we are assigning to an iterator. if (getTemplateKind(lexp->getType()) != VectorIteratorKind) return state; return handleAssign(state, MR, rexp, LC); }
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); } }
bool OSAtomicChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { const ProgramState *state = C.getState(); const Expr *Callee = CE->getCallee(); SVal L = state->getSVal(Callee); const FunctionDecl *FD = L.getAsFunctionDecl(); if (!FD) return false; const IdentifierInfo *II = FD->getIdentifier(); if (!II) return false; StringRef FName(II->getName()); // Check for compare and swap. if (FName.startswith("OSAtomicCompareAndSwap") || FName.startswith("objc_atomicCompareAndSwap")) return evalOSAtomicCompareAndSwap(C, CE); // FIXME: Other atomics. return false; }
bool DoubleFetchChecker::isLocTainted(ProgramStateRef state, SVal loc) const{ if (MaxTag == -1) return false; else{ const MemRegion *mrptr = loc.getAsRegion(); if(!mrptr) std::cout<<"(isLocTainted) getAsRegion failed!"<<std::endl; const TaintList *tl = state->get<LocalVarMap>(mrptr); if (tl){ return true; } return false; } }
void CallAndMessageChecker::checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const { SVal Arg = C.getSVal(DE->getArgument()); if (Arg.isUndef()) { StringRef Desc; ExplodedNode *N = C.generateSink(); if (!N) return; if (!BT_cxx_delete_undef) BT_cxx_delete_undef.reset( new BuiltinBug(this, "Uninitialized argument value")); if (DE->isArrayFormAsWritten()) Desc = "Argument to 'delete[]' is uninitialized"; else Desc = "Argument to 'delete' is uninitialized"; BugType *BT = BT_cxx_delete_undef.get(); auto R = llvm::make_unique<BugReport>(*BT, Desc, N); bugreporter::trackNullOrUndefValue(N, DE, *R); C.emitReport(std::move(R)); return; } }
void UndefinedAssignmentChecker::checkBind(SVal location, SVal val, const Stmt *StoreE, CheckerContext &C) const { if (!val.isUndef()) return; ExplodedNode *N = C.generateSink(); if (!N) return; const char *str = "Assigned value is garbage or undefined"; if (!BT) BT.reset(new BuiltinBug(str)); // Generate a report for this bug. const Expr *ex = 0; while (StoreE) { if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) { if (B->isCompoundAssignmentOp()) { ProgramStateRef state = C.getState(); if (state->getSVal(B->getLHS(), C.getLocationContext()).isUndef()) { str = "The left expression of the compound assignment is an " "uninitialized value. The computed value will also be garbage"; ex = B->getLHS(); break; } } ex = B->getRHS(); break; } if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) { const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); ex = VD->getInit(); } break; } BugReport *R = new BugReport(*BT, str, N); if (ex) { R->addRange(ex->getSourceRange()); bugreporter::trackNullOrUndefValue(N, ex, *R); } C.EmitReport(R); }
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; SVal LV = C.getSVal(B->getLHS()); SVal RV = C.getSVal(B->getRHS()); 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.generateNonFatalErrorNode()) { 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)); } }
// on a member call, first check the args for any bad iterators // then, check to see if it is a call to a function that will invalidate // the iterators void IteratorsChecker::checkPreStmt(const CXXMemberCallExpr *MCE, CheckerContext &C) const { // Check the arguments. checkArgs(C, MCE); const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()); if (!ME) return; // Make sure we have the right kind of container. const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ME->getBase()); if (!DRE || getTemplateKind(DRE->getType()) != VectorKind) return; SVal tsv = C.getState()->getSVal(DRE); // Get the MemRegion associated with the container instance. const MemRegion *MR = tsv.getAsRegion(); if (!MR) return; // If we are calling a function that invalidates iterators, mark them // appropriately by finding matching instances. const ProgramState *state = C.getState(); StringRef mName = ME->getMemberDecl()->getName(); if (llvm::StringSwitch<bool>(mName) .Cases("insert", "reserve", "push_back", true) .Cases("erase", "pop_back", "clear", "resize", true) .Default(false)) { // If there was a 'reserve' call, assume iterators are good. if (!state->contains<CalledReserved>(MR)) state = invalidateIterators(state, MR, ME); } // Keep track of instances that have called 'reserve' // note: do this after we invalidate any iterators by calling // 'reserve' itself. if (mName == "reserve") state = state->add<CalledReserved>(MR); if (state != C.getState()) C.addTransition(state); }
void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, CheckerContext &C) const { // Check for dereference of an undefined value. if (l.isUndef()) { if (ExplodedNode *N = C.generateSink()) { if (!BT_undef) BT_undef.reset(new BuiltinBug("Dereference of undefined pointer value")); BugReport *report = new BugReport(*BT_undef, BT_undef->getDescription(), N); bugreporter::addTrackNullOrUndefValueVisitor(N, bugreporter::GetDerefExpr(N), report); report->disablePathPruning(); C.EmitReport(report); } return; } DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l); // Check for null dereferences. if (!isa<Loc>(location)) return; ProgramStateRef state = C.getState(); ProgramStateRef notNullState, nullState; llvm::tie(notNullState, nullState) = state->assume(location); // The explicit NULL case. if (nullState) { if (!notNullState) { reportBug(nullState, S, C); return; } // Otherwise, we have the case where the location could either be // null or not-null. Record the error node as an "implicit" null // dereference. if (ExplodedNode *N = C.generateSink(nullState)) { ImplicitNullDerefEvent event = { l, isLoad, N, &C.getBugReporter() }; dispatchEvent(event); } } // From this point forward, we know that the location is not null. C.addTransition(notNullState); }
SymbolRef DoubleFetchChecker::getSymbolRef(SVal val) const { if(val.isConstant()){ std::cout<<"--->(getSymbolRef) failed! IsConstant."<<"\tval is:"<<toStr(val)<<std::endl; return NULL; } if(val.isUnknownOrUndef()){ std::cout<<"--->(getSymbolRef) failed! IsUnknownOrUndef."<<"\tval is:"<<toStr(val)<<std::endl; return NULL; } const SymExpr * SE = val.getAsSymExpr(); if (SE != NULL){ //std::cout<<"--->(getSymbolRef) getAsSymExpr succeed!"<<std::endl; return SE; } else{ //std::cout<<"--->(getSymbolRef) getAsSymExpr failed!, try get memregion"<<"\tval is:"<<toStr(val)<<std::endl; const MemRegion *Reg = val.getAsRegion(); if(!Reg){ std::cout<<"--->(getSymbolRef) getAsRegion failed!"<<"\tval is:"<<toStr(val)<<std::endl; return NULL; } else{ if (const SymbolicRegion *SR = dyn_cast_or_null<SymbolicRegion>(Reg)){ //std::cout<<"--->(getSymbolRef) getAsRegion succeed."<<std::endl; return SR->getSymbol(); } else{ std::cout<<"--->(getSymbolRef) memRegion get symbolref failed."<<std::endl; return NULL; } } } }
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 TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const { if (ExplodedNode *N = C.generateSink(C.getState())) { if (!DivZeroBug) DivZeroBug.reset(new BuiltinBug(this, "Division by zero")); auto R = llvm::make_unique<BugReport>( *DivZeroBug, "Value being compared against zero has already been used " "for division", N); R->addVisitor(llvm::make_unique<DivisionBRVisitor>(Val.getAsSymbol(), C.getStackFrame())); C.emitReport(std::move(R)); } }
bool ScanReachableSymbols::scan(SVal val) { if (loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&val)) return scan(X->getRegion()); if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&val)) return scan(X->getLoc()); if (SymbolRef Sym = val.getAsSymbol()) return visitor.VisitSymbol(Sym); if (nonloc::CompoundVal *X = dyn_cast<nonloc::CompoundVal>(&val)) return scan(*X); return true; }
bool StoreManager::FindUniqueBinding::HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R, SVal val) { SymbolRef SymV = val.getAsLocSymbol(); if (!SymV || SymV != Sym) return true; if (Binding) { First = false; return false; } else Binding = R; return true; }
// Check if the location is a freed symbolic region. void MallocChecker::checkLocation(SVal l, bool isLoad,CheckerContext &C) const { SymbolRef Sym = l.getLocSymbolInBase(); if (Sym) { const RefState *RS = C.getState()->get<RegionState>(Sym); if (RS && RS->isReleased()) { if (ExplodedNode *N = C.generateNode()) { if (!BT_UseFree) BT_UseFree.reset(new BuiltinBug("Use dynamically allocated memory " "after it is freed.")); BugReport *R = new BugReport(*BT_UseFree, BT_UseFree->getDescription(), N); C.EmitReport(R); } } } }
Store BasicStoreManager::Bind(Store store, Loc loc, SVal V) { if (isa<loc::ConcreteInt>(loc)) return store; const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion(); ASTContext &C = StateMgr.getContext(); // Special case: handle store of pointer values (Loc) to pointers via // a cast to intXX_t*, void*, etc. This is needed to handle // OSCompareAndSwap32Barrier/OSCompareAndSwap64Barrier. if (isa<Loc>(V) || isa<nonloc::LocAsInteger>(V)) if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { // FIXME: Should check for index 0. QualType T = ER->getLocationType(C); if (isHigherOrderRawPtr(T, C)) R = ER->getSuperRegion(); } if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R))) return store; const TypedRegion *TyR = cast<TypedRegion>(R); // Do not bind to arrays. We need to explicitly check for this so that // we do not encounter any weirdness of trying to load/store from arrays. if (TyR->isBoundable() && TyR->getValueType(C)->isArrayType()) return store; if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&V)) { // Only convert 'V' to a location iff the underlying region type // is a location as well. // FIXME: We are allowing a store of an arbitrary location to // a pointer. We may wish to flag a type error here if the types // are incompatible. This may also cause lots of breakage // elsewhere. Food for thought. if (TyR->isBoundable() && Loc::IsLocType(TyR->getValueType(C))) V = X->getLoc(); } BindingsTy B = GetBindings(store); return V.isUnknown() ? VBFactory.Remove(B, R).getRoot() : VBFactory.Add(B, R, V).getRoot(); }
void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) { const MemRegion *lockR = lock.getAsRegion(); if (!lockR) return; const GRState *state = C.getState(); // Record that the lock was released. // FIXME: Handle unlocking locks that were never acquired. This may // require IPA for wrappers. const GRState *unlockState = state->remove<LockSet>(lockR); if (state == unlockState) return; C.addTransition(C.generateNode(CE, unlockState)); }
static bool regionMatchesCXXRecordType(SVal V, QualType Ty) { const MemRegion *MR = V.getAsRegion(); if (!MR) return true; const auto *TVR = dyn_cast<TypedValueRegion>(MR); if (!TVR) return true; const CXXRecordDecl *RD = TVR->getValueType()->getAsCXXRecordDecl(); if (!RD) return true; const CXXRecordDecl *Expected = Ty->getPointeeCXXRecordDecl(); if (!Expected) Expected = Ty->getAsCXXRecordDecl(); return Expected->getCanonicalDecl() == RD->getCanonicalDecl(); }
void ObjCSelfInitChecker::checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const { // Allow assignment of anything to self. Self is a local variable in the // initializer, so it is legal to assign anything to it, like results of // static functions/method calls. After self is assigned something we cannot // reason about, stop enforcing the rules. // (Only continue checking if the assigned value should be treated as self.) if ((isSelfVar(loc, C)) && !hasSelfFlag(val, SelfFlag_InitRes, C) && !hasSelfFlag(val, SelfFlag_Self, C) && !isSelfVar(val, C)) { // Stop tracking the checker-specific state in the state. ProgramStateRef State = C.getState(); State = State->remove<CalledInit>(); if (SymbolRef sym = loc.getAsSymbol()) State = State->remove<SelfFlag>(sym); C.addTransition(State); } }
/// CastRetrievedVal - Used by subclasses of StoreManager to implement /// implicit casts that arise from loads from regions that are reinterpreted /// as another region. SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R, QualType castTy, bool performTestOnly) { if (castTy.isNull() || V.isUnknownOrUndef()) return V; ASTContext &Ctx = svalBuilder.getContext(); if (performTestOnly) { // Automatically translate references to pointers. QualType T = R->getValueType(); if (const ReferenceType *RT = T->getAs<ReferenceType>()) T = Ctx.getPointerType(RT->getPointeeType()); assert(svalBuilder.getContext().hasSameUnqualifiedType(castTy, T)); return V; } return svalBuilder.dispatchCast(V, castTy); }
/// When a symbol is assumed to be nil, remove it from the set of symbols /// require to be nil. ProgramStateRef ObjCDeallocChecker::evalAssume(ProgramStateRef State, SVal Cond, bool Assumption) const { if (State->get<UnreleasedIvarMap>().isEmpty()) return State; auto *CondBSE = dyn_cast_or_null<BinarySymExpr>(Cond.getAsSymExpr()); if (!CondBSE) return State; BinaryOperator::Opcode OpCode = CondBSE->getOpcode(); if (Assumption) { if (OpCode != BO_EQ) return State; } else { if (OpCode != BO_NE) return State; } SymbolRef NullSymbol = nullptr; if (auto *SIE = dyn_cast<SymIntExpr>(CondBSE)) { const llvm::APInt &RHS = SIE->getRHS(); if (RHS != 0) return State; NullSymbol = SIE->getLHS(); } else if (auto *SIE = dyn_cast<IntSymExpr>(CondBSE)) { const llvm::APInt &LHS = SIE->getLHS(); if (LHS != 0) return State; NullSymbol = SIE->getRHS(); } else { return State; } SymbolRef InstanceSymbol = getInstanceSymbolFromIvarSymbol(NullSymbol); if (!InstanceSymbol) return State; State = removeValueRequiringRelease(State, InstanceSymbol, NullSymbol); return State; }
SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) { if (Base.isUnknownOrUndef()) return Base; Loc BaseL = Base.castAs<Loc>(); const SubRegion* BaseR = nullptr; switch (BaseL.getSubKind()) { case loc::MemRegionValKind: BaseR = cast<SubRegion>(BaseL.castAs<loc::MemRegionVal>().getRegion()); break; case loc::GotoLabelKind: // These are anormal cases. Flag an undefined value. return UndefinedVal(); case loc::ConcreteIntKind: // While these seem funny, this can happen through casts. // FIXME: What we should return is the field offset, not base. For example, // add the field offset to the integer value. That way things // like this work properly: &(((struct foo *) 0xa)->f) // However, that's not easy to fix without reducing our abilities // to catch null pointer dereference. Eg., ((struct foo *)0x0)->f = 7 // is a null dereference even though we're dereferencing offset of f // rather than null. Coming up with an approach that computes offsets // over null pointers properly while still being able to catch null // dereferences might be worth it. return Base; default: llvm_unreachable("Unhandled Base."); } // NOTE: We must have this check first because ObjCIvarDecl is a subclass // of FieldDecl. if (const auto *ID = dyn_cast<ObjCIvarDecl>(D)) return loc::MemRegionVal(MRMgr.getObjCIvarRegion(ID, BaseR)); return loc::MemRegionVal(MRMgr.getFieldRegion(cast<FieldDecl>(D), BaseR)); }
std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ ProgramPoint P = N->getLocation(); const CallExitEnd *CExit = dyn_cast<CallExitEnd>(&P); assert(CExit && "Stack Hints should be constructed at CallExitEnd points."); // FIXME: Use CallEvent to abstract this over all calls. const Stmt *CallSite = CExit->getCalleeContext()->getCallSite(); const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite); if (!CE) return ""; if (!N) return getMessageForSymbolNotFound(); // Check if one of the parameters are set to the interesting symbol. ProgramStateRef State = N->getState(); const LocationContext *LCtx = N->getLocationContext(); unsigned ArgIndex = 0; for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I, ++ArgIndex){ SVal SV = State->getSVal(*I, LCtx); // Check if the variable corresponding to the symbol is passed by value. SymbolRef AS = SV.getAsLocSymbol(); if (AS == Sym) { return getMessageForArg(*I, ArgIndex); } // Check if the parameter is a pointer to the symbol. if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) { SVal PSV = State->getSVal(Reg->getRegion()); SymbolRef AS = PSV.getAsLocSymbol(); if (AS == Sym) { return getMessageForArg(*I, ArgIndex); } } } // Check if we are returning the interesting symbol. SVal SV = State->getSVal(CE, LCtx); SymbolRef RetSym = SV.getAsLocSymbol(); if (RetSym == Sym) { return getMessageForReturn(CE); } return getMessageForSymbolNotFound(); }
std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ if (!N) return getMessageForSymbolNotFound(); ProgramPoint P = N->getLocation(); CallExitEnd CExit = P.castAs<CallExitEnd>(); // FIXME: Use CallEvent to abstract this over all calls. const Stmt *CallSite = CExit.getCalleeContext()->getCallSite(); const auto *CE = dyn_cast_or_null<CallExpr>(CallSite); if (!CE) return {}; // Check if one of the parameters are set to the interesting symbol. unsigned ArgIndex = 0; for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I, ++ArgIndex){ SVal SV = N->getSVal(*I); // Check if the variable corresponding to the symbol is passed by value. SymbolRef AS = SV.getAsLocSymbol(); if (AS == Sym) { return getMessageForArg(*I, ArgIndex); } // Check if the parameter is a pointer to the symbol. if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) { // Do not attempt to dereference void*. if ((*I)->getType()->isVoidPointerType()) continue; SVal PSV = N->getState()->getSVal(Reg->getRegion()); SymbolRef AS = PSV.getAsLocSymbol(); if (AS == Sym) { return getMessageForArg(*I, ArgIndex); } } } // Check if we are returning the interesting symbol. SVal SV = N->getSVal(CE); SymbolRef RetSym = SV.getAsLocSymbol(); if (RetSym == Sym) { return getMessageForReturn(CE); } return getMessageForSymbolNotFound(); }
ProgramStateRef ProgramState::assumeInBound(DefinedOrUnknownSVal Idx, DefinedOrUnknownSVal UpperBound, bool Assumption, QualType indexTy) const { if (Idx.isUnknown() || UpperBound.isUnknown()) return this; // Build an expression for 0 <= Idx < UpperBound. // This is the same as Idx + MIN < UpperBound + MIN, if overflow is allowed. // FIXME: This should probably be part of SValBuilder. ProgramStateManager &SM = getStateManager(); SValBuilder &svalBuilder = SM.getSValBuilder(); ASTContext &Ctx = svalBuilder.getContext(); // Get the offset: the minimum value of the array index type. BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); // FIXME: This should be using ValueManager::ArrayindexTy...somehow. if (indexTy.isNull()) indexTy = Ctx.IntTy; nonloc::ConcreteInt Min(BVF.getMinValue(indexTy)); // Adjust the index. SVal newIdx = svalBuilder.evalBinOpNN(this, BO_Add, cast<NonLoc>(Idx), Min, indexTy); if (newIdx.isUnknownOrUndef()) return this; // Adjust the upper bound. SVal newBound = svalBuilder.evalBinOpNN(this, BO_Add, cast<NonLoc>(UpperBound), Min, indexTy); if (newBound.isUnknownOrUndef()) return this; // Build the actual comparison. SVal inBound = svalBuilder.evalBinOpNN(this, BO_LT, cast<NonLoc>(newIdx), cast<NonLoc>(newBound), Ctx.IntTy); if (inBound.isUnknownOrUndef()) return this; // Finally, let the constraint manager take care of it. ConstraintManager &CM = SM.getConstraintManager(); return CM.assume(this, cast<DefinedSVal>(inBound), Assumption); }