// Check various ways a symbol can be invalidated. // Stop tracking symbols when a value escapes as a result of checkBind. // A value escapes in three possible cases: // (1) We are binding to something that is not a memory region. // (2) We are binding to a MemRegion that does not have stack storage // (3) We are binding to a MemRegion with stack storage that the store // does not understand. void SimpleStreamChecker::checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const { // Are we storing to something that causes the value to "escape"? bool escapes = true; ProgramStateRef state = C.getState(); if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&loc)) { escapes = !regionLoc->getRegion()->hasStackStorage(); if (!escapes) { // To test (3), generate a new state with the binding added. If it is // the same state, then it escapes (since the store cannot represent // the binding). Do this only if we know that the store is not supposed // to generate the same state. SVal StoredVal = state->getSVal(regionLoc->getRegion()); if (StoredVal != val) escapes = (state == (state->bindLoc(*regionLoc, val))); } } // If our store can represent the binding and we aren't storing to something // that doesn't have local storage then just return the state and // continue as is. if (!escapes) return; // Otherwise, find all symbols referenced by 'val' that we are tracking // and stop tracking them. state = state->scanReachableSymbols<StopTrackingCallback>(val).getState(); C.addTransition(state); }
void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME, ExplodedNode *Pred, ExplodedNodeSet &Dst) { StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens(); ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); // Bind the temporary object to the value of the expression. Then bind // the expression to the location of the object. SVal V = state->getSVal(tempExpr, LCtx); // If the object is a record, the constructor will have already created // a temporary object region. If it is not, we need to copy the value over. if (!ME->getType()->isRecordType()) { const MemRegion *R = svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, LCtx); SVal L = loc::MemRegionVal(R); state = state->bindLoc(L, V); V = L; } Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, V)); }
void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME, ExplodedNode *Pred, ExplodedNodeSet &Dst) { StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens(); ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); // Bind the temporary object to the value of the expression. Then bind // the expression to the location of the object. SVal V = state->getSVal(tempExpr, LCtx); // If the value is already a CXXTempObjectRegion, it is fine as it is. // Otherwise, create a new CXXTempObjectRegion, and copy the value into it. const MemRegion *MR = V.getAsRegion(); if (!MR || !isa<CXXTempObjectRegion>(MR)) { const MemRegion *R = svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, LCtx); SVal L = loc::MemRegionVal(R); state = state->bindLoc(L, V); V = L; } Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, V)); }
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)); }
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::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); }
void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME, ExplodedNode *Pred, ExplodedNodeSet &Dst) { StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens(); ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); // Bind the temporary object to the value of the expression. Then bind // the expression to the location of the object. SVal V = state->getSVal(tempExpr, Pred->getLocationContext()); const MemRegion *R = svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, LCtx); state = state->bindLoc(loc::MemRegionVal(R), V); Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, loc::MemRegionVal(R))); }
void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, const MemRegion *Dest, const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst) { StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall())) return; // Create the context for 'this' region. const StackFrameContext *SFC = AnalysisDeclContexts.getContext(DD)-> getStackFrame(Pred->getLocationContext(), S, currentBuilderContext->getBlock(), currentStmtIdx); CallEnter PP(S, SFC, Pred->getLocationContext()); ProgramStateRef state = Pred->getState(); state = state->bindLoc(svalBuilder.getCXXThis(DD->getParent(), SFC), loc::MemRegionVal(Dest)); Bldr.generateNode(PP, Pred, state); }
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); }
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); }
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)); }
void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // FIXME: Much of this should eventually migrate to CXXAllocatorCall. // Also, we need to decide how allocators actually work -- they're not // really part of the CXXNewExpr because they happen BEFORE the // CXXConstructExpr subexpression. See PR12014 for some discussion. StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); unsigned blockCount = currBldrCtx->blockCount(); const LocationContext *LCtx = Pred->getLocationContext(); DefinedOrUnknownSVal symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx, CNE->getType(), blockCount); ProgramStateRef State = Pred->getState(); CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<CXXAllocatorCall> Call = CEMgr.getCXXAllocatorCall(CNE, State, LCtx); // Invalidate placement args. // FIXME: Once we figure out how we want allocators to work, // we should be using the usual pre-/(default-)eval-/post-call checks here. State = Call->invalidateRegions(blockCount); if (CNE->isArray()) { // FIXME: allocating an array requires simulating the constructors. // For now, just return a symbolicated region. const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion(); QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType(); const ElementRegion *EleReg = getStoreManager().GetElementZeroRegion(NewReg, ObjTy); State = State->BindExpr(CNE, Pred->getLocationContext(), loc::MemRegionVal(EleReg)); Bldr.generateNode(CNE, Pred, State); return; } // FIXME: Once we have proper support for CXXConstructExprs inside // CXXNewExpr, we need to make sure that the constructed object is not // immediately invalidated here. (The placement call should happen before // the constructor call anyway.) FunctionDecl *FD = CNE->getOperatorNew(); if (FD && FD->isReservedGlobalPlacementOperator()) { // Non-array placement new should always return the placement location. SVal PlacementLoc = State->getSVal(CNE->getPlacementArg(0), LCtx); State = State->BindExpr(CNE, LCtx, PlacementLoc); } else { State = State->BindExpr(CNE, LCtx, symVal); } // If the type is not a record, we won't have a CXXConstructExpr as an // initializer. Copy the value over. if (const Expr *Init = CNE->getInitializer()) { if (!isa<CXXConstructExpr>(Init)) { QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType(); (void)ObjTy; assert(!ObjTy->isRecordType()); SVal Location = State->getSVal(CNE, LCtx); if (isa<Loc>(Location)) State = State->bindLoc(cast<Loc>(Location), State->getSVal(Init, LCtx)); } } Bldr.generateNode(CNE, Pred, State); }
void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { CanQualType T = getContext().getCanonicalType(BE->getType()); const BlockDecl *BD = BE->getBlockDecl(); // Get the value of the block itself. SVal V = svalBuilder.getBlockPointer(BD, 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(); auto CI = BD->capture_begin(); auto CE = BD->capture_end(); for (; I != E; ++I) { const VarRegion *capturedR = I.getCapturedRegion(); const VarRegion *originalR = I.getOriginalRegion(); // If the capture had a copy expression, use the result of evaluating // that expression, otherwise use the original value. // We rely on the invariant that the block declaration's capture variables // are a prefix of the BlockDataRegion's referenced vars (which may include // referenced globals, etc.) to enable fast lookup of the capture for a // given referenced var. const Expr *copyExpr = nullptr; if (CI != CE) { assert(CI->getVariable() == capturedR->getDecl()); copyExpr = CI->getCopyExpr(); CI++; } if (capturedR != originalR) { SVal originalV; const LocationContext *LCtx = Pred->getLocationContext(); if (copyExpr) { originalV = State->getSVal(copyExpr, LCtx); } else { originalV = State->getSVal(loc::MemRegionVal(originalR)); } State = State->bindLoc(loc::MemRegionVal(capturedR), originalV, LCtx); } } } 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); }
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); }