const MemRegion * ExprEngine::getRegionForConstructedObject(const CXXConstructExpr *CE, ExplodedNode *Pred) { const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); // See if we're constructing an existing region by looking at the next // element in the CFG. if (auto Elem = findElementDirectlyInitializedByCurrentConstructor()) { if (Optional<CFGStmt> StmtElem = Elem->getAs<CFGStmt>()) { auto *DS = cast<DeclStmt>(StmtElem->getStmt()); if (const auto *Var = dyn_cast<VarDecl>(DS->getSingleDecl())) { if (Var->getInit() && Var->getInit()->IgnoreImplicit() == CE) { SVal LValue = State->getLValue(Var, LCtx); QualType Ty = Var->getType(); LValue = makeZeroElementRegion(State, LValue, Ty); return LValue.getAsRegion(); } } } else if (Optional<CFGInitializer> InitElem = Elem->getAs<CFGInitializer>()) { const CXXCtorInitializer *Init = InitElem->getInitializer(); assert(Init->isAnyMemberInitializer()); const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl()); Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor, LCtx->getCurrentStackFrame()); SVal ThisVal = State->getSVal(ThisPtr); const ValueDecl *Field; SVal FieldVal; if (Init->isIndirectMemberInitializer()) { Field = Init->getIndirectMember(); FieldVal = State->getLValue(Init->getIndirectMember(), ThisVal); } else { Field = Init->getMember(); FieldVal = State->getLValue(Init->getMember(), ThisVal); } QualType Ty = Field->getType(); FieldVal = makeZeroElementRegion(State, FieldVal, Ty); return FieldVal.getAsRegion(); } // FIXME: This will eventually need to handle new-expressions as well. // Don't forget to update the pre-constructor initialization code in // ExprEngine::VisitCXXConstructExpr. } // If we couldn't find an existing region to construct into, assume we're // constructing a temporary. MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); return MRMgr.getCXXTempObjectRegion(CE, LCtx); }
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)); }
/// Assumes that the collection elements are non-nil. /// /// This only applies if the collection is one of those known not to contain /// nil values. static ProgramStateRef checkElementNonNil(CheckerContext &C, ProgramStateRef State, const ObjCForCollectionStmt *FCS) { if (!State) return nullptr; // See if the collection is one where we /know/ the elements are non-nil. if (!isKnownNonNilCollectionType(FCS->getCollection()->getType())) return State; const LocationContext *LCtx = C.getLocationContext(); const Stmt *Element = FCS->getElement(); // FIXME: Copied from ExprEngineObjC. Optional<Loc> ElementLoc; if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) { const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl()); assert(ElemDecl->getInit() == nullptr); ElementLoc = State->getLValue(ElemDecl, LCtx); } else { ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>(); } if (!ElementLoc) return State; // Go ahead and assume the value is non-nil. SVal Val = State->getSVal(*ElementLoc); return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true); }
static bool checkSelfIvarsForInvariantViolation(ProgramStateRef State, const LocationContext *LocCtxt) { auto *MD = dyn_cast<ObjCMethodDecl>(LocCtxt->getDecl()); if (!MD || !MD->isInstanceMethod()) return false; const ImplicitParamDecl *SelfDecl = LocCtxt->getSelfDecl(); if (!SelfDecl) return false; SVal SelfVal = State->getSVal(State->getRegion(SelfDecl, LocCtxt)); const ObjCObjectPointerType *SelfType = dyn_cast<ObjCObjectPointerType>(SelfDecl->getType()); if (!SelfType) return false; const ObjCInterfaceDecl *ID = SelfType->getInterfaceDecl(); if (!ID) return false; for (const auto *IvarDecl : ID->ivars()) { SVal LV = State->getLValue(IvarDecl, SelfVal); if (checkValueAtLValForInvariantViolation(State, LV, IvarDecl->getType())) { return true; } } return false; }
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); // 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()) V = CLLoc; } B.generateNode(CL, Pred, State->BindExpr(CL, LCtx, V)); }
static bool checkParamsForPreconditionViolation(const ParamVarDeclRange &Params, ProgramStateRef State, const LocationContext *LocCtxt) { for (const auto *ParamDecl : Params) { if (ParamDecl->isParameterPack()) break; if (getNullabilityAnnotation(ParamDecl->getType()) != Nullability::Nonnull) continue; auto RegVal = State->getLValue(ParamDecl, LocCtxt) .template getAs<loc::MemRegionVal>(); if (!RegVal) continue; auto ParamValue = State->getSVal(RegVal->getRegion()) .template getAs<DefinedOrUnknownSVal>(); if (!ParamValue) continue; if (getNullConstraint(*ParamValue, State) == NullConstraint::IsNull) { return true; } } return false; }
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); }
/// If this is the beginning of -dealloc, mark the values initially stored in /// instance variables that must be released by the end of -dealloc /// as unreleased in the state. void ObjCDeallocChecker::checkBeginFunction( CheckerContext &C) const { initIdentifierInfoAndSelectors(C.getASTContext()); // Only do this if the current method is -dealloc. SVal SelfVal; if (!isInInstanceDealloc(C, SelfVal)) return; SymbolRef SelfSymbol = SelfVal.getAsSymbol(); const LocationContext *LCtx = C.getLocationContext(); ProgramStateRef InitialState = C.getState(); ProgramStateRef State = InitialState; SymbolSet::Factory &F = State->getStateManager().get_context<SymbolSet>(); // Symbols that must be released by the end of the -dealloc; SymbolSet RequiredReleases = F.getEmptySet(); // If we're an inlined -dealloc, we should add our symbols to the existing // set from our subclass. if (const SymbolSet *CurrSet = State->get<UnreleasedIvarMap>(SelfSymbol)) RequiredReleases = *CurrSet; for (auto *PropImpl : getContainingObjCImpl(LCtx)->property_impls()) { ReleaseRequirement Requirement = getDeallocReleaseRequirement(PropImpl); if (Requirement != ReleaseRequirement::MustRelease) continue; SVal LVal = State->getLValue(PropImpl->getPropertyIvarDecl(), SelfVal); Optional<Loc> LValLoc = LVal.getAs<Loc>(); if (!LValLoc) continue; SVal InitialVal = State->getSVal(LValLoc.getValue()); SymbolRef Symbol = InitialVal.getAsSymbol(); if (!Symbol || !isa<SymbolRegionValue>(Symbol)) continue; // Mark the value as requiring a release. RequiredReleases = F.add(RequiredReleases, Symbol); } if (!RequiredReleases.isEmpty()) { State = State->set<UnreleasedIvarMap>(SelfSymbol, RequiredReleases); } if (State != InitialState) { C.addTransition(State); } }
/// Returns a region representing the first element of a (possibly /// multi-dimensional) array. /// /// On return, \p Ty will be set to the base type of the array. /// /// If the type is not an array type at all, the original value is returned. static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue, QualType &Ty) { SValBuilder &SVB = State->getStateManager().getSValBuilder(); ASTContext &Ctx = SVB.getContext(); while (const ArrayType *AT = Ctx.getAsArrayType(Ty)) { Ty = AT->getElementType(); LValue = State->getLValue(Ty, SVB.makeZeroArrayIndex(), LValue); } return LValue; }
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); }
void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); SVal baseVal = state->getSVal(Ex->getBase(), LCtx); SVal location = state->getLValue(Ex->getDecl(), baseVal); ExplodedNodeSet dstIvar; StmtNodeBuilder Bldr(Pred, dstIvar, *currentBuilderContext); Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, location)); // Perform the post-condition check of the ObjCIvarRefExpr and store // the created nodes in 'Dst'. getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this); }
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; }
void ExprEngine::VisitCXXDestructor(QualType ObjectType, const MemRegion *Dest, const Stmt *S, bool IsBaseDtor, ExplodedNode *Pred, ExplodedNodeSet &Dst) { const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); // FIXME: We need to run the same destructor on every element of the array. // This workaround will just run the first destructor (which will still // invalidate the entire array). // This is a loop because of multidimensional arrays. while (const ArrayType *AT = getContext().getAsArrayType(ObjectType)) { ObjectType = AT->getElementType(); Dest = State->getLValue(ObjectType, getSValBuilder().makeZeroArrayIndex(), loc::MemRegionVal(Dest)).getAsRegion(); } const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl(); assert(RecordDecl && "Only CXXRecordDecls should have destructors"); const CXXDestructorDecl *DtorDecl = RecordDecl->getDestructor(); CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<CXXDestructorCall> Call = CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, IsBaseDtor, State, LCtx); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), Call->getSourceRange().getBegin(), "Error evaluating destructor"); ExplodedNodeSet DstPreCall; getCheckerManager().runCheckersForPreCall(DstPreCall, Pred, *Call, *this); ExplodedNodeSet DstInvalidated; StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx); for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) defaultEvalCall(Bldr, *I, *Call); ExplodedNodeSet DstPostCall; getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated, *Call, *this); }
void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { const VarDecl *VD = CS->getExceptionDecl(); if (!VD) { Dst.Add(Pred); return; } const LocationContext *LCtx = Pred->getLocationContext(); SVal V = svalBuilder.conjureSymbolVal(CS, LCtx, VD->getType(), currBldrCtx->blockCount()); ProgramStateRef state = Pred->getState(); state = state->bindLoc(state->getLValue(VD, LCtx), V); StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); Bldr.generateNode(CS, Pred, state); }
/// Returns the value stored in the 'success_' field of the passed-in /// AssertionResult instance. SVal GTestChecker::getAssertionResultSuccessFieldValue( const CXXRecordDecl *AssertionResultDecl, SVal Instance, ProgramStateRef State) const { DeclContext::lookup_result Result = AssertionResultDecl->lookup(SuccessII); if (Result.empty()) return UnknownVal(); auto *SuccessField = dyn_cast<FieldDecl>(Result.front()); if (!SuccessField) return UnknownVal(); Optional<Loc> FieldLoc = State->getLValue(SuccessField, Instance).getAs<Loc>(); if (!FieldLoc.hasValue()) return UnknownVal(); return State->getSVal(*FieldLoc); }
/// 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 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) { SVal Field = State->getLValue(*CurField, V); SVal InitExpr = State->getSVal(*i, LocCtxt); State = State->bindLoc(Field, InitExpr); } // 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 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)); }
std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction( const Expr *E, ProgramStateRef State, const LocationContext *LCtx, const ConstructionContext *CC, EvalCallOptions &CallOpts) { SValBuilder &SVB = getSValBuilder(); MemRegionManager &MRMgr = SVB.getRegionManager(); ASTContext &ACtx = SVB.getContext(); // See if we're constructing an existing region by looking at the // current construction context. if (CC) { switch (CC->getKind()) { case ConstructionContext::CXX17ElidedCopyVariableKind: case ConstructionContext::SimpleVariableKind: { const auto *DSCC = cast<VariableConstructionContext>(CC); const auto *DS = DSCC->getDeclStmt(); const auto *Var = cast<VarDecl>(DS->getSingleDecl()); SVal LValue = State->getLValue(Var, LCtx); QualType Ty = Var->getType(); LValue = makeZeroElementRegion(State, LValue, Ty, CallOpts.IsArrayCtorOrDtor); State = addObjectUnderConstruction(State, DSCC->getDeclStmt(), LCtx, LValue); return std::make_pair(State, LValue); } case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind: case ConstructionContext::SimpleConstructorInitializerKind: { const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC); const auto *Init = ICC->getCXXCtorInitializer(); assert(Init->isAnyMemberInitializer()); const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl()); Loc ThisPtr = SVB.getCXXThis(CurCtor, LCtx->getStackFrame()); SVal ThisVal = State->getSVal(ThisPtr); const ValueDecl *Field; SVal FieldVal; if (Init->isIndirectMemberInitializer()) { Field = Init->getIndirectMember(); FieldVal = State->getLValue(Init->getIndirectMember(), ThisVal); } else { Field = Init->getMember(); FieldVal = State->getLValue(Init->getMember(), ThisVal); } QualType Ty = Field->getType(); FieldVal = makeZeroElementRegion(State, FieldVal, Ty, CallOpts.IsArrayCtorOrDtor); State = addObjectUnderConstruction(State, Init, LCtx, FieldVal); return std::make_pair(State, FieldVal); } case ConstructionContext::NewAllocatedObjectKind: { if (AMgr.getAnalyzerOptions().MayInlineCXXAllocator) { const auto *NECC = cast<NewAllocatedObjectConstructionContext>(CC); const auto *NE = NECC->getCXXNewExpr(); SVal V = *getObjectUnderConstruction(State, NE, LCtx); if (const SubRegion *MR = dyn_cast_or_null<SubRegion>(V.getAsRegion())) { if (NE->isArray()) { // TODO: In fact, we need to call the constructor for every // allocated element, not just the first one! CallOpts.IsArrayCtorOrDtor = true; return std::make_pair( State, loc::MemRegionVal(getStoreManager().GetElementZeroRegion( MR, NE->getType()->getPointeeType()))); } return std::make_pair(State, V); } // TODO: Detect when the allocator returns a null pointer. // Constructor shall not be called in this case. } break; } case ConstructionContext::SimpleReturnedValueKind: case ConstructionContext::CXX17ElidedCopyReturnedValueKind: { // The temporary is to be managed by the parent stack frame. // So build it in the parent stack frame if we're not in the // top frame of the analysis. const StackFrameContext *SFC = LCtx->getStackFrame(); if (const LocationContext *CallerLCtx = SFC->getParent()) { auto RTC = (*SFC->getCallSiteBlock())[SFC->getIndex()] .getAs<CFGCXXRecordTypedCall>(); if (!RTC) { // We were unable to find the correct construction context for the // call in the parent stack frame. This is equivalent to not being // able to find construction context at all. break; } return prepareForObjectConstruction( cast<Expr>(SFC->getCallSite()), State, CallerLCtx, RTC->getConstructionContext(), CallOpts); } else { // We are on the top frame of the analysis. We do not know where is the // object returned to. Conjure a symbolic region for the return value. // TODO: We probably need a new MemRegion kind to represent the storage // of that SymbolicRegion, so that we cound produce a fancy symbol // instead of an anonymous conjured symbol. // TODO: Do we need to track the region to avoid having it dead // too early? It does die too early, at least in C++17, but because // putting anything into a SymbolicRegion causes an immediate escape, // it doesn't cause any leak false positives. const auto *RCC = cast<ReturnedValueConstructionContext>(CC); // Make sure that this doesn't coincide with any other symbol // conjured for the returned expression. static const int TopLevelSymRegionTag = 0; const Expr *RetE = RCC->getReturnStmt()->getRetValue(); assert(RetE && "Void returns should not have a construction context"); QualType ReturnTy = RetE->getType(); QualType RegionTy = ACtx.getPointerType(ReturnTy); SVal V = SVB.conjureSymbolVal(&TopLevelSymRegionTag, RetE, SFC, RegionTy, currBldrCtx->blockCount()); return std::make_pair(State, V); } llvm_unreachable("Unhandled return value construction context!"); } case ConstructionContext::ElidedTemporaryObjectKind: { assert(AMgr.getAnalyzerOptions().ShouldElideConstructors); const auto *TCC = cast<ElidedTemporaryObjectConstructionContext>(CC); const CXXBindTemporaryExpr *BTE = TCC->getCXXBindTemporaryExpr(); const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr(); const CXXConstructExpr *CE = TCC->getConstructorAfterElision(); // Support pre-C++17 copy elision. We'll have the elidable copy // constructor in the AST and in the CFG, but we'll skip it // and construct directly into the final object. This call // also sets the CallOpts flags for us. SVal V; // If the elided copy/move constructor is not supported, there's still // benefit in trying to model the non-elided constructor. // Stash our state before trying to elide, as it'll get overwritten. ProgramStateRef PreElideState = State; EvalCallOptions PreElideCallOpts = CallOpts; std::tie(State, V) = prepareForObjectConstruction( CE, State, LCtx, TCC->getConstructionContextAfterElision(), CallOpts); // FIXME: This definition of "copy elision has not failed" is unreliable. // It doesn't indicate that the constructor will actually be inlined // later; it is still up to evalCall() to decide. if (!CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion) { // Remember that we've elided the constructor. State = addObjectUnderConstruction(State, CE, LCtx, V); // Remember that we've elided the destructor. if (BTE) State = elideDestructor(State, BTE, LCtx); // Instead of materialization, shamelessly return // the final object destination. if (MTE) State = addObjectUnderConstruction(State, MTE, LCtx, V); return std::make_pair(State, V); } else { // Copy elision failed. Revert the changes and proceed as if we have // a simple temporary. State = PreElideState; CallOpts = PreElideCallOpts; } LLVM_FALLTHROUGH; } case ConstructionContext::SimpleTemporaryObjectKind: { const auto *TCC = cast<TemporaryObjectConstructionContext>(CC); const CXXBindTemporaryExpr *BTE = TCC->getCXXBindTemporaryExpr(); const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr(); SVal V = UnknownVal(); if (MTE) { if (const ValueDecl *VD = MTE->getExtendingDecl()) { assert(MTE->getStorageDuration() != SD_FullExpression); if (!VD->getType()->isReferenceType()) { // We're lifetime-extended by a surrounding aggregate. // Automatic destructors aren't quite working in this case // on the CFG side. We should warn the caller about that. // FIXME: Is there a better way to retrieve this information from // the MaterializeTemporaryExpr? CallOpts.IsTemporaryLifetimeExtendedViaAggregate = true; } } if (MTE->getStorageDuration() == SD_Static || MTE->getStorageDuration() == SD_Thread) V = loc::MemRegionVal(MRMgr.getCXXStaticTempObjectRegion(E)); } if (V.isUnknown()) V = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx)); if (BTE) State = addObjectUnderConstruction(State, BTE, LCtx, V); if (MTE) State = addObjectUnderConstruction(State, MTE, LCtx, V); CallOpts.IsTemporaryCtorOrDtor = true; return std::make_pair(State, V); } case ConstructionContext::ArgumentKind: { // Arguments are technically temporaries. CallOpts.IsTemporaryCtorOrDtor = true; const auto *ACC = cast<ArgumentConstructionContext>(CC); const Expr *E = ACC->getCallLikeExpr(); unsigned Idx = ACC->getIndex(); const CXXBindTemporaryExpr *BTE = ACC->getCXXBindTemporaryExpr(); CallEventManager &CEMgr = getStateManager().getCallEventManager(); SVal V = UnknownVal(); auto getArgLoc = [&](CallEventRef<> Caller) -> Optional<SVal> { const LocationContext *FutureSFC = Caller->getCalleeStackFrame(); // Return early if we are unable to reliably foresee // the future stack frame. if (!FutureSFC) return None; // This should be equivalent to Caller->getDecl() for now, but // FutureSFC->getDecl() is likely to support better stuff (like // virtual functions) earlier. const Decl *CalleeD = FutureSFC->getDecl(); // FIXME: Support for variadic arguments is not implemented here yet. if (CallEvent::isVariadic(CalleeD)) return None; // Operator arguments do not correspond to operator parameters // because this-argument is implemented as a normal argument in // operator call expressions but not in operator declarations. const VarRegion *VR = Caller->getParameterLocation( *Caller->getAdjustedParameterIndex(Idx)); if (!VR) return None; return loc::MemRegionVal(VR); }; if (const auto *CE = dyn_cast<CallExpr>(E)) { CallEventRef<> Caller = CEMgr.getSimpleCall(CE, State, LCtx); if (auto OptV = getArgLoc(Caller)) V = *OptV; else break; State = addObjectUnderConstruction(State, {CE, Idx}, LCtx, V); } else if (const auto *CCE = dyn_cast<CXXConstructExpr>(E)) { // Don't bother figuring out the target region for the future // constructor because we won't need it. CallEventRef<> Caller = CEMgr.getCXXConstructorCall(CCE, /*Target=*/nullptr, State, LCtx); if (auto OptV = getArgLoc(Caller)) V = *OptV; else break; State = addObjectUnderConstruction(State, {CCE, Idx}, LCtx, V); } else if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) { CallEventRef<> Caller = CEMgr.getObjCMethodCall(ME, State, LCtx); if (auto OptV = getArgLoc(Caller)) V = *OptV; else break; State = addObjectUnderConstruction(State, {ME, Idx}, LCtx, V); } assert(!V.isUnknown()); if (BTE) State = addObjectUnderConstruction(State, BTE, LCtx, V); return std::make_pair(State, V); } } } // If we couldn't find an existing region to construct into, assume we're // constructing a temporary. Notify the caller of our failure. CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; return std::make_pair( State, loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx))); }
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, ExplodedNode *Pred, ExplodedNodeSet &destNodes) { const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); const MemRegion *Target = 0; switch (CE->getConstructionKind()) { case CXXConstructExpr::CK_Complete: { // See if we're constructing an existing region by looking at the next // element in the CFG. const CFGBlock *B = currBldrCtx->getBlock(); if (currStmtIdx + 1 < B->size()) { CFGElement Next = (*B)[currStmtIdx+1]; // Is this a constructor for a local variable? if (const CFGStmt *StmtElem = dyn_cast<CFGStmt>(&Next)) { if (const DeclStmt *DS = dyn_cast<DeclStmt>(StmtElem->getStmt())) { if (const VarDecl *Var = dyn_cast<VarDecl>(DS->getSingleDecl())) { if (Var->getInit()->IgnoreImplicit() == CE) { QualType Ty = Var->getType(); if (const ArrayType *AT = getContext().getAsArrayType(Ty)) { // FIXME: Handle arrays, which run the same constructor for // every element. This workaround will just run the first // constructor (which should still invalidate the entire array). SVal Base = State->getLValue(Var, LCtx); Target = State->getLValue(AT->getElementType(), getSValBuilder().makeZeroArrayIndex(), Base).getAsRegion(); } else { Target = State->getLValue(Var, LCtx).getAsRegion(); } } } } } // Is this a constructor for a member? if (const CFGInitializer *InitElem = dyn_cast<CFGInitializer>(&Next)) { const CXXCtorInitializer *Init = InitElem->getInitializer(); assert(Init->isAnyMemberInitializer()); const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl()); Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor, LCtx->getCurrentStackFrame()); SVal ThisVal = State->getSVal(ThisPtr); if (Init->isIndirectMemberInitializer()) { SVal Field = State->getLValue(Init->getIndirectMember(), ThisVal); Target = Field.getAsRegion(); } else { SVal Field = State->getLValue(Init->getMember(), ThisVal); Target = Field.getAsRegion(); } } // FIXME: This will eventually need to handle new-expressions as well. } // If we couldn't find an existing region to construct into, assume we're // constructing a temporary. if (!Target) { MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); Target = MRMgr.getCXXTempObjectRegion(CE, LCtx); } break; } case CXXConstructExpr::CK_NonVirtualBase: case CXXConstructExpr::CK_VirtualBase: case CXXConstructExpr::CK_Delegating: { const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl()); Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor, LCtx->getCurrentStackFrame()); SVal ThisVal = State->getSVal(ThisPtr); if (CE->getConstructionKind() == CXXConstructExpr::CK_Delegating) { Target = ThisVal.getAsRegion(); } else { // Cast to the base type. QualType BaseTy = CE->getType(); SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy); Target = BaseVal.getAsRegion(); } break; } } CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<CXXConstructorCall> Call = CEMgr.getCXXConstructorCall(CE, Target, State, LCtx); ExplodedNodeSet DstPreVisit; getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this); ExplodedNodeSet DstPreCall; getCheckerManager().runCheckersForPreCall(DstPreCall, DstPreVisit, *Call, *this); ExplodedNodeSet DstInvalidated; StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx); for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) defaultEvalCall(Bldr, *I, *Call); ExplodedNodeSet DstPostCall; getCheckerManager().runCheckersForPostCall(DstPostCall, DstInvalidated, *Call, *this); getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, CE, *this); }
void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // FIXME: static variables may have an initializer, but the second // time a function is called those values may not be current. // This may need to be reflected in the CFG. // Assumption: The CFG has one DeclStmt per Decl. const Decl *D = *DS->decl_begin(); if (!D || !isa<VarDecl>(D)) { //TODO:AZ: remove explicit insertion after refactoring is done. Dst.insert(Pred); return; } // FIXME: all pre/post visits should eventually be handled by ::Visit(). ExplodedNodeSet dstPreVisit; getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this); StmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext); const VarDecl *VD = dyn_cast<VarDecl>(D); for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end(); I!=E; ++I) { ExplodedNode *N = *I; ProgramStateRef state = N->getState(); // Decls without InitExpr are not initialized explicitly. const LocationContext *LC = N->getLocationContext(); if (const Expr *InitEx = VD->getInit()) { SVal InitVal = state->getSVal(InitEx, LC); if (InitVal == state->getLValue(VD, LC) || (VD->getType()->isArrayType() && isa<CXXConstructExpr>(InitEx->IgnoreImplicit()))) { // We constructed the object directly in the variable. // No need to bind anything. B.generateNode(DS, N, state); } else { // We bound the temp obj region to the CXXConstructExpr. Now recover // the lazy compound value when the variable is not a reference. if (AMgr.getLangOpts().CPlusPlus && VD->getType()->isRecordType() && !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){ InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion()); assert(isa<nonloc::LazyCompoundVal>(InitVal)); } // Recover some path-sensitivity if a scalar value evaluated to // UnknownVal. if (InitVal.isUnknown()) { QualType Ty = InitEx->getType(); if (InitEx->isGLValue()) { Ty = getContext().getPointerType(Ty); } InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, LC, Ty, currentBuilderContext->getCurrentBlockCount()); } B.takeNodes(N); ExplodedNodeSet Dst2; evalBind(Dst2, DS, N, state->getLValue(VD, LC), InitVal, true); B.addNodes(Dst2); } } else { B.generateNode(DS, N,state->bindDeclWithNoInit(state->getRegion(VD, LC))); } } }
void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // ObjCForCollectionStmts are processed in two places. This method // handles the case where an ObjCForCollectionStmt* occurs as one of the // statements within a basic block. This transfer function does two things: // // (1) binds the next container value to 'element'. This creates a new // node in the ExplodedGraph. // // (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating // whether or not the container has any more elements. This value // will be tested in ProcessBranch. We need to explicitly bind // this value because a container can contain nil elements. // // FIXME: Eventually this logic should actually do dispatches to // 'countByEnumeratingWithState:objects:count:' (NSFastEnumeration). // This will require simulating a temporary NSFastEnumerationState, either // through an SVal or through the use of MemRegions. This value can // be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop // terminates we reclaim the temporary (it goes out of scope) and we // we can test if the SVal is 0 or if the MemRegion is null (depending // on what approach we take). // // For now: simulate (1) by assigning either a symbol or nil if the // container is empty. Thus this transfer function will by default // result in state splitting. const Stmt *elem = S->getElement(); ProgramStateRef state = Pred->getState(); SVal elementV; if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) { const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl()); assert(elemD->getInit() == 0); elementV = state->getLValue(elemD, Pred->getLocationContext()); } else { elementV = state->getSVal(elem, Pred->getLocationContext()); } ExplodedNodeSet dstLocation; evalLocation(dstLocation, S, elem, Pred, state, elementV, NULL, false); ExplodedNodeSet Tmp; StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext); for (ExplodedNodeSet::iterator NI = dstLocation.begin(), NE = dstLocation.end(); NI!=NE; ++NI) { Pred = *NI; ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); // Handle the case where the container still has elements. SVal TrueV = svalBuilder.makeTruthVal(1); ProgramStateRef hasElems = state->BindExpr(S, LCtx, TrueV); // Handle the case where the container has no elements. SVal FalseV = svalBuilder.makeTruthVal(0); ProgramStateRef noElems = state->BindExpr(S, LCtx, FalseV); if (loc::MemRegionVal *MV = dyn_cast<loc::MemRegionVal>(&elementV)) if (const TypedValueRegion *R = dyn_cast<TypedValueRegion>(MV->getRegion())) { // FIXME: The proper thing to do is to really iterate over the // container. We will do this with dispatch logic to the store. // For now, just 'conjure' up a symbolic value. QualType T = R->getValueType(); assert(Loc::isLocType(T)); unsigned Count = currentBuilderContext->getCurrentBlockCount(); SymbolRef Sym = SymMgr.getConjuredSymbol(elem, LCtx, T, Count); SVal V = svalBuilder.makeLoc(Sym); hasElems = hasElems->bindLoc(elementV, V); // Bind the location to 'nil' on the false branch. SVal nilV = svalBuilder.makeIntVal(0, T); noElems = noElems->bindLoc(elementV, nilV); } // Create the new nodes. Bldr.generateNode(S, Pred, hasElems); Bldr.generateNode(S, Pred, noElems); } // Finally, run any custom checkers. // FIXME: Eventually all pre- and post-checks should live in VisitStmt. getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this); }
void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // Assumption: The CFG has one DeclStmt per Decl. const VarDecl *VD = dyn_cast_or_null<VarDecl>(*DS->decl_begin()); if (!VD) { //TODO:AZ: remove explicit insertion after refactoring is done. Dst.insert(Pred); return; } // FIXME: all pre/post visits should eventually be handled by ::Visit(). ExplodedNodeSet dstPreVisit; getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this); StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx); for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end(); I!=E; ++I) { ExplodedNode *N = *I; ProgramStateRef state = N->getState(); const LocationContext *LC = N->getLocationContext(); // Decls without InitExpr are not initialized explicitly. if (const Expr *InitEx = VD->getInit()) { // Note in the state that the initialization has occurred. ExplodedNode *UpdatedN = N; SVal InitVal = state->getSVal(InitEx, LC); if (isa<CXXConstructExpr>(InitEx->IgnoreImplicit())) { // We constructed the object directly in the variable. // No need to bind anything. B.generateNode(DS, UpdatedN, state); } else { // We bound the temp obj region to the CXXConstructExpr. Now recover // the lazy compound value when the variable is not a reference. if (AMgr.getLangOpts().CPlusPlus && VD->getType()->isRecordType() && !VD->getType()->isReferenceType()) { if (Optional<loc::MemRegionVal> M = InitVal.getAs<loc::MemRegionVal>()) { InitVal = state->getSVal(M->getRegion()); assert(InitVal.getAs<nonloc::LazyCompoundVal>()); } } // Recover some path-sensitivity if a scalar value evaluated to // UnknownVal. if (InitVal.isUnknown()) { QualType Ty = InitEx->getType(); if (InitEx->isGLValue()) { Ty = getContext().getPointerType(Ty); } InitVal = svalBuilder.conjureSymbolVal(0, InitEx, LC, Ty, currBldrCtx->blockCount()); } B.takeNodes(UpdatedN); ExplodedNodeSet Dst2; evalBind(Dst2, DS, UpdatedN, state->getLValue(VD, LC), InitVal, true); B.addNodes(Dst2); } } else { B.generateNode(DS, N, state); } } }
static const MemRegion *getRegionForConstructedObject( const CXXConstructExpr *CE, ExplodedNode *Pred, ExprEngine &Eng, unsigned int CurrStmtIdx) { const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); const NodeBuilderContext &CurrBldrCtx = Eng.getBuilderContext(); // See if we're constructing an existing region by looking at the next // element in the CFG. const CFGBlock *B = CurrBldrCtx.getBlock(); unsigned int NextStmtIdx = CurrStmtIdx + 1; if (NextStmtIdx < B->size()) { CFGElement Next = (*B)[NextStmtIdx]; // Is this a destructor? If so, we might be in the middle of an assignment // to a local or member: look ahead one more element to see what we find. while (Next.getAs<CFGImplicitDtor>() && NextStmtIdx + 1 < B->size()) { ++NextStmtIdx; Next = (*B)[NextStmtIdx]; } // Is this a constructor for a local variable? if (Optional<CFGStmt> StmtElem = Next.getAs<CFGStmt>()) { if (const DeclStmt *DS = dyn_cast<DeclStmt>(StmtElem->getStmt())) { if (const VarDecl *Var = dyn_cast<VarDecl>(DS->getSingleDecl())) { if (Var->getInit() && Var->getInit()->IgnoreImplicit() == CE) { SVal LValue = State->getLValue(Var, LCtx); QualType Ty = Var->getType(); LValue = makeZeroElementRegion(State, LValue, Ty); return LValue.getAsRegion(); } } } } // Is this a constructor for a member? if (Optional<CFGInitializer> InitElem = Next.getAs<CFGInitializer>()) { const CXXCtorInitializer *Init = InitElem->getInitializer(); assert(Init->isAnyMemberInitializer()); const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl()); Loc ThisPtr = Eng.getSValBuilder().getCXXThis(CurCtor, LCtx->getCurrentStackFrame()); SVal ThisVal = State->getSVal(ThisPtr); const ValueDecl *Field; SVal FieldVal; if (Init->isIndirectMemberInitializer()) { Field = Init->getIndirectMember(); FieldVal = State->getLValue(Init->getIndirectMember(), ThisVal); } else { Field = Init->getMember(); FieldVal = State->getLValue(Init->getMember(), ThisVal); } QualType Ty = Field->getType(); FieldVal = makeZeroElementRegion(State, FieldVal, Ty); return FieldVal.getAsRegion(); } // FIXME: This will eventually need to handle new-expressions as well. // Don't forget to update the pre-constructor initialization code in // ExprEngine::VisitCXXConstructExpr. } // If we couldn't find an existing region to construct into, assume we're // constructing a temporary. MemRegionManager &MRMgr = Eng.getSValBuilder().getRegionManager(); return MRMgr.getCXXTempObjectRegion(CE, LCtx); }
SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op, Loc lhs, NonLoc rhs, QualType resultTy) { if (op >= BO_PtrMemD && op <= BO_PtrMemI) { if (auto PTMSV = rhs.getAs<nonloc::PointerToMember>()) { if (PTMSV->isNullMemberPointer()) return UndefinedVal(); if (const FieldDecl *FD = PTMSV->getDeclAs<FieldDecl>()) { SVal Result = lhs; for (const auto &I : *PTMSV) Result = StateMgr.getStoreManager().evalDerivedToBase( Result, I->getType(),I->isVirtual()); return state->getLValue(FD, Result); } } return rhs; } assert(!BinaryOperator::isComparisonOp(op) && "arguments to comparison ops must be of the same type"); // Special case: rhs is a zero constant. if (rhs.isZeroConstant()) return lhs; // We are dealing with pointer arithmetic. // Handle pointer arithmetic on constant values. if (Optional<nonloc::ConcreteInt> rhsInt = rhs.getAs<nonloc::ConcreteInt>()) { if (Optional<loc::ConcreteInt> lhsInt = lhs.getAs<loc::ConcreteInt>()) { const llvm::APSInt &leftI = lhsInt->getValue(); assert(leftI.isUnsigned()); llvm::APSInt rightI(rhsInt->getValue(), /* isUnsigned */ true); // Convert the bitwidth of rightI. This should deal with overflow // since we are dealing with concrete values. rightI = rightI.extOrTrunc(leftI.getBitWidth()); // Offset the increment by the pointer size. llvm::APSInt Multiplicand(rightI.getBitWidth(), /* isUnsigned */ true); rightI *= Multiplicand; // Compute the adjusted pointer. switch (op) { case BO_Add: rightI = leftI + rightI; break; case BO_Sub: rightI = leftI - rightI; break; default: llvm_unreachable("Invalid pointer arithmetic operation"); } return loc::ConcreteInt(getBasicValueFactory().getValue(rightI)); } } // Handle cases where 'lhs' is a region. if (const MemRegion *region = lhs.getAsRegion()) { rhs = convertToArrayIndex(rhs).castAs<NonLoc>(); SVal index = UnknownVal(); const MemRegion *superR = nullptr; // We need to know the type of the pointer in order to add an integer to it. // Depending on the type, different amount of bytes is added. QualType elementType; if (const ElementRegion *elemReg = dyn_cast<ElementRegion>(region)) { assert(op == BO_Add || op == BO_Sub); index = evalBinOpNN(state, op, elemReg->getIndex(), rhs, getArrayIndexType()); superR = elemReg->getSuperRegion(); elementType = elemReg->getElementType(); } else if (isa<SubRegion>(region)) { assert(op == BO_Add || op == BO_Sub); index = (op == BO_Add) ? rhs : evalMinus(rhs); superR = region; // TODO: Is this actually reliable? Maybe improving our MemRegion // hierarchy to provide typed regions for all non-void pointers would be // better. For instance, we cannot extend this towards LocAsInteger // operations, where result type of the expression is integer. if (resultTy->isAnyPointerType()) elementType = resultTy->getPointeeType(); } if (Optional<NonLoc> indexV = index.getAs<NonLoc>()) { return loc::MemRegionVal(MemMgr.getElementRegion(elementType, *indexV, superR, getContext())); } } return UnknownVal(); }