/// Insert a diagnostic piece at function exit /// if a function parameter is annotated as "os_consumed", /// but it does not actually consume the reference. static std::shared_ptr<PathDiagnosticEventPiece> annotateConsumedSummaryMismatch(const ExplodedNode *N, CallExitBegin &CallExitLoc, const SourceManager &SM, CallEventManager &CEMgr) { const ExplodedNode *CN = getCalleeNode(N); if (!CN) return nullptr; CallEventRef<> Call = CEMgr.getCaller(N->getStackFrame(), N->getState()); std::string sbuf; llvm::raw_string_ostream os(sbuf); ArrayRef<const ParmVarDecl *> Parameters = Call->parameters(); for (unsigned I=0; I < Call->getNumArgs() && I < Parameters.size(); ++I) { const ParmVarDecl *PVD = Parameters[I]; if (!PVD->hasAttr<OSConsumedAttr>()) continue; if (SymbolRef SR = Call->getArgSVal(I).getAsLocSymbol()) { const RefVal *CountBeforeCall = getRefBinding(CN->getState(), SR); const RefVal *CountAtExit = getRefBinding(N->getState(), SR); if (!CountBeforeCall || !CountAtExit) continue; unsigned CountBefore = CountBeforeCall->getCount(); unsigned CountAfter = CountAtExit->getCount(); bool AsExpected = CountBefore > 0 && CountAfter == CountBefore - 1; if (!AsExpected) { os << "Parameter '"; PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(), /*Qualified=*/false); os << "' is marked as consuming, but the function did not consume " << "the reference\n"; } } } if (os.str().empty()) return nullptr; // FIXME: remove the code duplication with NoStoreFuncVisitor. PathDiagnosticLocation L; if (const ReturnStmt *RS = CallExitLoc.getReturnStmt()) { L = PathDiagnosticLocation::createBegin(RS, SM, N->getLocationContext()); } else { L = PathDiagnosticLocation( Call->getRuntimeDefinition().getDecl()->getSourceRange().getEnd(), SM); } return std::make_shared<PathDiagnosticEventPiece>(L, os.str()); }
void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred, const CallEvent &CallTemplate, const EvalCallOptions &CallOpts) { // Make sure we have the most recent state attached to the call. ProgramStateRef State = Pred->getState(); CallEventRef<> Call = CallTemplate.cloneWithState(State); // Special-case trivial assignment operators. if (isTrivialObjectAssignment(*Call)) { performTrivialCopy(Bldr, Pred, *Call); return; } // Try to inline the call. // The origin expression here is just used as a kind of checksum; // this should still be safe even for CallEvents that don't come from exprs. const Expr *E = Call->getOriginExpr(); ProgramStateRef InlinedFailedState = getInlineFailedState(State, E); if (InlinedFailedState) { // If we already tried once and failed, make sure we don't retry later. State = InlinedFailedState; } else { RuntimeDefinition RD = Call->getRuntimeDefinition(); const Decl *D = RD.getDecl(); if (shouldInlineCall(*Call, D, Pred, CallOpts)) { if (RD.mayHaveOtherDefinitions()) { AnalyzerOptions &Options = getAnalysisManager().options; // Explore with and without inlining the call. if (Options.getIPAMode() == IPAK_DynamicDispatchBifurcate) { BifurcateCall(RD.getDispatchRegion(), *Call, D, Bldr, Pred); return; } // Don't inline if we're not in any dynamic dispatch mode. if (Options.getIPAMode() != IPAK_DynamicDispatch) { conservativeEvalCall(*Call, Bldr, Pred, State); return; } } // We are not bifurcating and we do have a Decl, so just inline. if (inlineCall(*Call, D, Bldr, Pred, State)) return; } } // If we can't inline it, handle the return value and invalidate the regions. conservativeEvalCall(*Call, Bldr, Pred, State); }
PathDiagnosticPiece * UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, BugReport &BR) { ProgramStateRef State = N->getState(); ProgramPoint ProgLoc = N->getLocation(); // We are only interested in visiting CallEnter nodes. Optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>(); if (!CEnter) return 0; // Check if one of the arguments is the region the visitor is tracking. CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager(); CallEventRef<> Call = CEMgr.getCaller(CEnter->getCalleeContext(), State); unsigned Idx = 0; for (CallEvent::param_iterator I = Call->param_begin(), E = Call->param_end(); I != E; ++I, ++Idx) { const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion(); // Are we tracking the argument or its subregion? if ( !ArgReg || (ArgReg != R && !R->isSubRegionOf(ArgReg->StripCasts()))) continue; // Check the function parameter type. const ParmVarDecl *ParamDecl = *I; assert(ParamDecl && "Formal parameter has no decl?"); QualType T = ParamDecl->getType(); if (!(T->isAnyPointerType() || T->isReferenceType())) { // Function can only change the value passed in by address. continue; } // If it is a const pointer value, the function does not intend to // change the value. if (T->getPointeeType().isConstQualified()) continue; // Mark the call site (LocationContext) as interesting if the value of the // argument is undefined or '0'/'NULL'. SVal BoundVal = State->getSVal(R); if (BoundVal.isUndef() || BoundVal.isZeroConstant()) { BR.markInteresting(CEnter->getCalleeContext()); return 0; } } return 0; }
void ExprEngine::VisitCXXDestructor(QualType ObjectType, const MemRegion *Dest, const Stmt *S, bool IsBaseDtor, ExplodedNode *Pred, ExplodedNodeSet &Dst, const EvalCallOptions &CallOpts) { assert(S && "A destructor without a trigger!"); const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl(); assert(RecordDecl && "Only CXXRecordDecls should have destructors"); const CXXDestructorDecl *DtorDecl = RecordDecl->getDestructor(); // FIXME: There should always be a Decl, otherwise the destructor call // shouldn't have been added to the CFG in the first place. if (!DtorDecl) { // Skip the invalid destructor. We cannot simply return because // it would interrupt the analysis instead. static SimpleProgramPointTag T("ExprEngine", "SkipInvalidDestructor"); // FIXME: PostImplicitCall with a null decl may crash elsewhere anyway. PostImplicitCall PP(/*Decl=*/nullptr, S->getEndLoc(), LCtx, &T); NodeBuilder Bldr(Pred, Dst, *currBldrCtx); Bldr.generateNode(PP, Pred->getState(), Pred); return; } 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, CallOpts); getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated, *Call, *this); }
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); }
static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call, const StackFrameContext *calleeCtx) { const Decl *RuntimeCallee = calleeCtx->getDecl(); const Decl *StaticDecl = Call->getDecl(); assert(RuntimeCallee); if (!StaticDecl) return true; return RuntimeCallee->getCanonicalDecl() != StaticDecl->getCanonicalDecl(); }
/** * Get line number for call event ref * @param call * @return line number as string */ std::string MPIBugReporter::lineNumber( const CallEventRef<> callEventRef) const { std::string lineNo = callEventRef->getSourceRange().getBegin().printToString( bugReporter_.getSourceManager()); // split written string into parts std::vector<std::string> strs = util::split(lineNo, ':'); return util::split(lineNo, ':').at(strs.size() - 2); }
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); }
/// The call exit is simulated with a sequence of nodes, which occur between /// CallExitBegin and CallExitEnd. The following operations occur between the /// two program points: /// 1. CallExitBegin (triggers the start of call exit sequence) /// 2. Bind the return value /// 3. Run Remove dead bindings to clean up the dead symbols from the callee. /// 4. CallExitEnd (switch to the caller context) /// 5. PostStmt<CallExpr> void ExprEngine::processCallExit(ExplodedNode *CEBNode) { // Step 1 CEBNode was generated before the call. PrettyStackTraceLocationContext CrashInfo(CEBNode->getLocationContext()); const StackFrameContext *calleeCtx = CEBNode->getLocationContext()->getCurrentStackFrame(); // The parent context might not be a stack frame, so make sure we // look up the first enclosing stack frame. const StackFrameContext *callerCtx = calleeCtx->getParent()->getCurrentStackFrame(); const Stmt *CE = calleeCtx->getCallSite(); ProgramStateRef state = CEBNode->getState(); // Find the last statement in the function and the corresponding basic block. const Stmt *LastSt = nullptr; const CFGBlock *Blk = nullptr; std::tie(LastSt, Blk) = getLastStmt(CEBNode); // Generate a CallEvent /before/ cleaning the state, so that we can get the // correct value for 'this' (if necessary). CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<> Call = CEMgr.getCaller(calleeCtx, state); // Step 2: generate node with bound return value: CEBNode -> BindedRetNode. // If the callee returns an expression, bind its value to CallExpr. if (CE) { if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) { const LocationContext *LCtx = CEBNode->getLocationContext(); SVal V = state->getSVal(RS, LCtx); // Ensure that the return type matches the type of the returned Expr. if (wasDifferentDeclUsedForInlining(Call, calleeCtx)) { QualType ReturnedTy = CallEvent::getDeclaredResultType(calleeCtx->getDecl()); if (!ReturnedTy.isNull()) { if (const Expr *Ex = dyn_cast<Expr>(CE)) { V = adjustReturnValue(V, Ex->getType(), ReturnedTy, getStoreManager()); } } } state = state->BindExpr(CE, callerCtx, V); } // Bind the constructed object value to CXXConstructExpr. if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) { loc::MemRegionVal This = svalBuilder.getCXXThis(CCE->getConstructor()->getParent(), calleeCtx); SVal ThisV = state->getSVal(This); // If the constructed object is a temporary prvalue, get its bindings. if (isTemporaryPRValue(CCE, ThisV)) ThisV = state->getSVal(ThisV.castAs<Loc>()); state = state->BindExpr(CCE, callerCtx, ThisV); } } // Step 3: BindedRetNode -> CleanedNodes // If we can find a statement and a block in the inlined function, run remove // dead bindings before returning from the call. This is important to ensure // that we report the issues such as leaks in the stack contexts in which // they occurred. ExplodedNodeSet CleanedNodes; if (LastSt && Blk && AMgr.options.AnalysisPurgeOpt != PurgeNone) { static SimpleProgramPointTag retValBind("ExprEngine", "Bind Return Value"); PostStmt Loc(LastSt, calleeCtx, &retValBind); bool isNew; ExplodedNode *BindedRetNode = G.getNode(Loc, state, false, &isNew); BindedRetNode->addPredecessor(CEBNode, G); if (!isNew) return; NodeBuilderContext Ctx(getCoreEngine(), Blk, BindedRetNode); currBldrCtx = &Ctx; // Here, we call the Symbol Reaper with 0 statement and callee location // context, telling it to clean up everything in the callee's context // (and its children). We use the callee's function body as a diagnostic // statement, with which the program point will be associated. removeDead(BindedRetNode, CleanedNodes, nullptr, calleeCtx, calleeCtx->getAnalysisDeclContext()->getBody(), ProgramPoint::PostStmtPurgeDeadSymbolsKind); currBldrCtx = nullptr; } else { CleanedNodes.Add(CEBNode); } for (ExplodedNodeSet::iterator I = CleanedNodes.begin(), E = CleanedNodes.end(); I != E; ++I) { // Step 4: Generate the CallExit and leave the callee's context. // CleanedNodes -> CEENode CallExitEnd Loc(calleeCtx, callerCtx); bool isNew; ProgramStateRef CEEState = (*I == CEBNode) ? state : (*I)->getState(); ExplodedNode *CEENode = G.getNode(Loc, CEEState, false, &isNew); CEENode->addPredecessor(*I, G); if (!isNew) return; // Step 5: Perform the post-condition check of the CallExpr and enqueue the // result onto the work list. // CEENode -> Dst -> WorkList NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), CEENode); SaveAndRestore<const NodeBuilderContext*> NBCSave(currBldrCtx, &Ctx); SaveAndRestore<unsigned> CBISave(currStmtIdx, calleeCtx->getIndex()); CallEventRef<> UpdatedCall = Call.cloneWithState(CEEState); ExplodedNodeSet DstPostCall; getCheckerManager().runCheckersForPostCall(DstPostCall, CEENode, *UpdatedCall, *this, /*WasInlined=*/true); ExplodedNodeSet Dst; if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) { getCheckerManager().runCheckersForPostObjCMessage(Dst, DstPostCall, *Msg, *this, /*WasInlined=*/true); } else if (CE) { getCheckerManager().runCheckersForPostStmt(Dst, DstPostCall, CE, *this, /*WasInlined=*/true); } else { Dst.insert(DstPostCall); } // Enqueue the next element in the block. for (ExplodedNodeSet::iterator PSI = Dst.begin(), PSE = Dst.end(); PSI != PSE; ++PSI) { Engine.getWorkList()->enqueue(*PSI, calleeCtx->getCallSiteBlock(), calleeCtx->getIndex()+1); } } }
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. unsigned blockCount = currBldrCtx->blockCount(); const LocationContext *LCtx = Pred->getLocationContext(); DefinedOrUnknownSVal symVal = UnknownVal(); FunctionDecl *FD = CNE->getOperatorNew(); bool IsStandardGlobalOpNewFunction = false; if (FD && !isa<CXXMethodDecl>(FD) && !FD->isVariadic()) { if (FD->getNumParams() == 2) { QualType T = FD->getParamDecl(1)->getType(); if (const IdentifierInfo *II = T.getBaseTypeIdentifier()) // NoThrow placement new behaves as a standard new. IsStandardGlobalOpNewFunction = II->getName().equals("nothrow_t"); } else // Placement forms are considered non-standard. IsStandardGlobalOpNewFunction = (FD->getNumParams() == 1); } // We assume all standard global 'operator new' functions allocate memory in // heap. We realize this is an approximation that might not correctly model // a custom global allocator. if (IsStandardGlobalOpNewFunction) symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount); else symVal = svalBuilder.conjureSymbolVal(nullptr, 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 (!State) return; // If this allocation function is not declared as non-throwing, failures // /must/ be signalled by exceptions, and thus the return value will never be // NULL. -fno-exceptions does not influence this semantics. // FIXME: GCC has a -fcheck-new option, which forces it to consider the case // where new can return NULL. If we end up supporting that option, we can // consider adding a check for it here. // C++11 [basic.stc.dynamic.allocation]p3. if (FD) { QualType Ty = FD->getType(); if (const FunctionProtoType *ProtoType = Ty->getAs<FunctionProtoType>()) if (!ProtoType->isNothrow(getContext())) State = State->assume(symVal, true); } StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); if (CNE->isArray()) { // FIXME: allocating an array requires simulating the constructors. // For now, just return a symbolicated region. const MemRegion *NewReg = symVal.castAs<loc::MemRegionVal>().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.) SVal Result = symVal; if (FD && FD->isReservedGlobalPlacementOperator()) { // Non-array placement new should always return the placement location. SVal PlacementLoc = State->getSVal(CNE->getPlacementArg(0), LCtx); Result = svalBuilder.evalCast(PlacementLoc, CNE->getType(), CNE->getPlacementArg(0)->getType()); } // Bind the address of the object, then check to see if we cached out. State = State->BindExpr(CNE, LCtx, Result); ExplodedNode *NewN = Bldr.generateNode(CNE, Pred, State); if (!NewN) return; // 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)) { assert(Bldr.getResults().size() == 1); Bldr.takeNodes(NewN); evalBind(Dst, CNE, NewN, Result, State->getSVal(Init, LCtx), /*FirstInit=*/IsStandardGlobalOpNewFunction); } } }
PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, const ExplodedNode *Pred, BugReporterContext &BRC, BugReport &BR) { if (Satisfied) return NULL; const ExplodedNode *StoreSite = 0; const Expr *InitE = 0; bool IsParam = false; // First see if we reached the declaration of the region. if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { if (Optional<PostStmt> P = Pred->getLocationAs<PostStmt>()) { if (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) { if (DS->getSingleDecl() == VR->getDecl()) { StoreSite = Pred; InitE = VR->getDecl()->getInit(); } } } } // Otherwise, see if this is the store site: // (1) Succ has this binding and Pred does not, i.e. this is // where the binding first occurred. // (2) Succ has this binding and is a PostStore node for this region, i.e. // the same binding was re-assigned here. if (!StoreSite) { if (Succ->getState()->getSVal(R) != V) return NULL; if (Pred->getState()->getSVal(R) == V) { Optional<PostStore> PS = Succ->getLocationAs<PostStore>(); if (!PS || PS->getLocationValue() != R) return NULL; } StoreSite = Succ; // If this is an assignment expression, we can track the value // being assigned. if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>()) if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) if (BO->isAssignmentOp()) InitE = BO->getRHS(); // If this is a call entry, the variable should be a parameter. // FIXME: Handle CXXThisRegion as well. (This is not a priority because // 'this' should never be NULL, but this visitor isn't just for NULL and // UndefinedVal.) if (Optional<CallEnter> CE = Succ->getLocationAs<CallEnter>()) { if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl()); ProgramStateManager &StateMgr = BRC.getStateManager(); CallEventManager &CallMgr = StateMgr.getCallEventManager(); CallEventRef<> Call = CallMgr.getCaller(CE->getCalleeContext(), Succ->getState()); InitE = Call->getArgExpr(Param->getFunctionScopeIndex()); IsParam = true; } } } if (!StoreSite) return NULL; Satisfied = true; // If we have an expression that provided the value, try to track where it // came from. if (InitE) { if (V.isUndef() || V.getAs<loc::ConcreteInt>()) { if (!IsParam) InitE = InitE->IgnoreParenCasts(); bugreporter::trackNullOrUndefValue(StoreSite, InitE, BR, IsParam); } else { ReturnVisitor::addVisitorIfNecessary(StoreSite, InitE->IgnoreParenCasts(), BR); } } if (!R->canPrintPretty()) return 0; // Okay, we've found the binding. Emit an appropriate message. SmallString<256> sbuf; llvm::raw_svector_ostream os(sbuf); if (Optional<PostStmt> PS = StoreSite->getLocationAs<PostStmt>()) { const Stmt *S = PS->getStmt(); const char *action = 0; const DeclStmt *DS = dyn_cast<DeclStmt>(S); const VarRegion *VR = dyn_cast<VarRegion>(R); if (DS) { action = "initialized to "; } else if (isa<BlockExpr>(S)) { action = "captured by block as "; if (VR) { // See if we can get the BlockVarRegion. ProgramStateRef State = StoreSite->getState(); SVal V = State->getSVal(S, PS->getLocationContext()); if (const BlockDataRegion *BDR = dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) { if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) { if (Optional<KnownSVal> KV = State->getSVal(OriginalR).getAs<KnownSVal>()) BR.addVisitor(new FindLastStoreBRVisitor(*KV, OriginalR)); } } } } if (action) { if (!R) return 0; os << '\''; R->printPretty(os); os << "' "; if (V.getAs<loc::ConcreteInt>()) { bool b = false; if (R->isBoundable()) { if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { if (TR->getValueType()->isObjCObjectPointerType()) { os << action << "nil"; b = true; } } } if (!b) os << action << "a null pointer value"; } else if (Optional<nonloc::ConcreteInt> CVal = V.getAs<nonloc::ConcreteInt>()) { os << action << CVal->getValue(); } else if (DS) { if (V.isUndef()) { if (isa<VarRegion>(R)) { const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); if (VD->getInit()) os << "initialized to a garbage value"; else os << "declared without an initial value"; } } else { os << "initialized here"; } } } } else if (StoreSite->getLocation().getAs<CallEnter>()) { if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl()); os << "Passing "; if (V.getAs<loc::ConcreteInt>()) { if (Param->getType()->isObjCObjectPointerType()) os << "nil object reference"; else os << "null pointer value"; } else if (V.isUndef()) { os << "uninitialized value"; } else if (Optional<nonloc::ConcreteInt> CI = V.getAs<nonloc::ConcreteInt>()) { os << "the value " << CI->getValue(); } else { os << "value"; } // Printed parameter indexes are 1-based, not 0-based. unsigned Idx = Param->getFunctionScopeIndex() + 1; os << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter '"; R->printPretty(os); os << '\''; } } if (os.str().empty()) { if (V.getAs<loc::ConcreteInt>()) { bool b = false; if (R->isBoundable()) { if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { if (TR->getValueType()->isObjCObjectPointerType()) { os << "nil object reference stored to "; b = true; } } } if (!b) os << "Null pointer value stored to "; } else if (V.isUndef()) { os << "Uninitialized value stored to "; } else if (Optional<nonloc::ConcreteInt> CV = V.getAs<nonloc::ConcreteInt>()) { os << "The value " << CV->getValue() << " is assigned to "; } else os << "Value assigned to "; os << '\''; R->printPretty(os); os << '\''; } // Construct a new PathDiagnosticPiece. ProgramPoint P = StoreSite->getLocation(); PathDiagnosticLocation L; if (P.getAs<CallEnter>() && InitE) L = PathDiagnosticLocation(InitE, BRC.getSourceManager(), P.getLocationContext()); else L = PathDiagnosticLocation::create(P, BRC.getSourceManager()); if (!L.isValid()) return NULL; return new PathDiagnosticEventPiece(L, os.str()); }
void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME, ExplodedNode *Pred, ExplodedNodeSet &Dst) { CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<ObjCMethodCall> Msg = CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext()); // Handle the previsits checks. ExplodedNodeSet dstPrevisit; getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred, *Msg, *this); ExplodedNodeSet dstGenericPrevisit; getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit, *Msg, *this); // Proceed with evaluate the message expression. ExplodedNodeSet dstEval; StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currentBuilderContext); for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(), DE = dstGenericPrevisit.end(); DI != DE; ++DI) { ExplodedNode *Pred = *DI; ProgramStateRef State = Pred->getState(); CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State); if (UpdatedMsg->isInstanceMessage()) { SVal recVal = UpdatedMsg->getReceiverSVal(); if (!recVal.isUndef()) { // Bifurcate the state into nil and non-nil ones. DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal); ProgramStateRef notNilState, nilState; llvm::tie(notNilState, nilState) = State->assume(receiverVal); // There are three cases: can be nil or non-nil, must be nil, must be // non-nil. We ignore must be nil, and merge the rest two into non-nil. // FIXME: This ignores many potential bugs (<rdar://problem/11733396>). // Revisit once we have lazier constraints. if (nilState && !notNilState) { continue; } // Check if the "raise" message was sent. assert(notNilState); if (Msg->getSelector() == RaiseSel) { // If we raise an exception, for now treat it as a sink. // Eventually we will want to handle exceptions properly. Bldr.generateNode(currentStmt, Pred, State, true); continue; } // Generate a transition to non-Nil state. if (notNilState != State) Pred = Bldr.generateNode(currentStmt, Pred, notNilState); } } else { // Check for special class methods. if (const ObjCInterfaceDecl *Iface = Msg->getReceiverInterface()) { if (!NSExceptionII) { ASTContext &Ctx = getContext(); NSExceptionII = &Ctx.Idents.get("NSException"); } if (isSubclass(Iface, NSExceptionII)) { enum { NUM_RAISE_SELECTORS = 2 }; // Lazily create a cache of the selectors. if (!NSExceptionInstanceRaiseSelectors) { ASTContext &Ctx = getContext(); NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS]; SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II; unsigned idx = 0; // raise:format: II.push_back(&Ctx.Idents.get("raise")); II.push_back(&Ctx.Idents.get("format")); NSExceptionInstanceRaiseSelectors[idx++] = Ctx.Selectors.getSelector(II.size(), &II[0]); // raise:format:arguments: II.push_back(&Ctx.Idents.get("arguments")); NSExceptionInstanceRaiseSelectors[idx++] = Ctx.Selectors.getSelector(II.size(), &II[0]); } Selector S = Msg->getSelector(); bool RaisesException = false; for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) { if (S == NSExceptionInstanceRaiseSelectors[i]) { RaisesException = true; break; } } if (RaisesException) { // If we raise an exception, for now treat it as a sink. // Eventually we will want to handle exceptions properly. Bldr.generateNode(currentStmt, Pred, Pred->getState(), true); continue; } } } } // Evaluate the call. defaultEvalCall(Bldr, Pred, *UpdatedMsg); } ExplodedNodeSet dstPostvisit; getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval, *Msg, *this); // Finally, perform the post-condition check of the ObjCMessageExpr and store // the created nodes in 'Dst'. getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit, *Msg, *this); }
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, ExplodedNode *Pred, ExplodedNodeSet &destNodes) { const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); SVal Target = UnknownVal(); if (Optional<SVal> ElidedTarget = getObjectUnderConstruction(State, CE, LCtx)) { // We've previously modeled an elidable constructor by pretending that it in // fact constructs into the correct target. This constructor can therefore // be skipped. Target = *ElidedTarget; StmtNodeBuilder Bldr(Pred, destNodes, *currBldrCtx); State = finishObjectConstruction(State, CE, LCtx); if (auto L = Target.getAs<Loc>()) State = State->BindExpr(CE, LCtx, State->getSVal(*L, CE->getType())); Bldr.generateNode(CE, Pred, State); return; } // FIXME: Handle arrays, which run the same constructor for every element. // For now, we just run the first constructor (which should still invalidate // the entire array). EvalCallOptions CallOpts; auto C = getCurrentCFGElement().getAs<CFGConstructor>(); assert(C || getCurrentCFGElement().getAs<CFGStmt>()); const ConstructionContext *CC = C ? C->getConstructionContext() : nullptr; switch (CE->getConstructionKind()) { case CXXConstructExpr::CK_Complete: { std::tie(State, Target) = prepareForObjectConstruction(CE, State, LCtx, CC, CallOpts); break; } case CXXConstructExpr::CK_VirtualBase: // Make sure we are not calling virtual base class initializers twice. // Only the most-derived object should initialize virtual base classes. if (const Stmt *Outer = LCtx->getStackFrame()->getCallSite()) { const CXXConstructExpr *OuterCtor = dyn_cast<CXXConstructExpr>(Outer); if (OuterCtor) { switch (OuterCtor->getConstructionKind()) { case CXXConstructExpr::CK_NonVirtualBase: case CXXConstructExpr::CK_VirtualBase: // Bail out! destNodes.Add(Pred); return; case CXXConstructExpr::CK_Complete: case CXXConstructExpr::CK_Delegating: break; } } } LLVM_FALLTHROUGH; case CXXConstructExpr::CK_NonVirtualBase: // In C++17, classes with non-virtual bases may be aggregates, so they would // be initialized as aggregates without a constructor call, so we may have // a base class constructed directly into an initializer list without // having the derived-class constructor call on the previous stack frame. // Initializer lists may be nested into more initializer lists that // correspond to surrounding aggregate initializations. // FIXME: For now this code essentially bails out. We need to find the // correct target region and set it. // FIXME: Instead of relying on the ParentMap, we should have the // trigger-statement (InitListExpr in this case) passed down from CFG or // otherwise always available during construction. if (dyn_cast_or_null<InitListExpr>(LCtx->getParentMap().getParent(CE))) { MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); Target = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(CE, LCtx)); CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; break; } LLVM_FALLTHROUGH; case CXXConstructExpr::CK_Delegating: { const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl()); Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor, LCtx->getStackFrame()); SVal ThisVal = State->getSVal(ThisPtr); if (CE->getConstructionKind() == CXXConstructExpr::CK_Delegating) { Target = ThisVal; } else { // Cast to the base type. bool IsVirtual = (CE->getConstructionKind() == CXXConstructExpr::CK_VirtualBase); SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, CE->getType(), IsVirtual); Target = BaseVal; } break; } } if (State != Pred->getState()) { static SimpleProgramPointTag T("ExprEngine", "Prepare for object construction"); ExplodedNodeSet DstPrepare; StmtNodeBuilder BldrPrepare(Pred, DstPrepare, *currBldrCtx); BldrPrepare.generateNode(CE, Pred, State, &T, ProgramPoint::PreStmtKind); assert(DstPrepare.size() <= 1); if (DstPrepare.size() == 0) return; Pred = *BldrPrepare.begin(); } CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<CXXConstructorCall> Call = CEMgr.getCXXConstructorCall(CE, Target.getAsRegion(), State, LCtx); ExplodedNodeSet DstPreVisit; getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this); // FIXME: Is it possible and/or useful to do this before PreStmt? ExplodedNodeSet PreInitialized; { StmtNodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx); for (ExplodedNodeSet::iterator I = DstPreVisit.begin(), E = DstPreVisit.end(); I != E; ++I) { ProgramStateRef State = (*I)->getState(); if (CE->requiresZeroInitialization()) { // FIXME: Once we properly handle constructors in new-expressions, we'll // need to invalidate the region before setting a default value, to make // sure there aren't any lingering bindings around. This probably needs // to happen regardless of whether or not the object is zero-initialized // to handle random fields of a placement-initialized object picking up // old bindings. We might only want to do it when we need to, though. // FIXME: This isn't actually correct for arrays -- we need to zero- // initialize the entire array, not just the first element -- but our // handling of arrays everywhere else is weak as well, so this shouldn't // actually make things worse. Placement new makes this tricky as well, // since it's then possible to be initializing one part of a multi- // dimensional array. State = State->bindDefaultZero(Target, LCtx); } Bldr.generateNode(CE, *I, State, /*tag=*/nullptr, ProgramPoint::PreStmtKind); } } ExplodedNodeSet DstPreCall; getCheckerManager().runCheckersForPreCall(DstPreCall, PreInitialized, *Call, *this); ExplodedNodeSet DstEvaluated; StmtNodeBuilder Bldr(DstPreCall, DstEvaluated, *currBldrCtx); if (CE->getConstructor()->isTrivial() && CE->getConstructor()->isCopyOrMoveConstructor() && !CallOpts.IsArrayCtorOrDtor) { // FIXME: Handle other kinds of trivial constructors as well. for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) performTrivialCopy(Bldr, *I, *Call); } else { for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) defaultEvalCall(Bldr, *I, *Call, CallOpts); } // If the CFG was constructed without elements for temporary destructors // and the just-called constructor created a temporary object then // stop exploration if the temporary object has a noreturn constructor. // This can lose coverage because the destructor, if it were present // in the CFG, would be called at the end of the full expression or // later (for life-time extended temporaries) -- but avoids infeasible // paths when no-return temporary destructors are used for assertions. const AnalysisDeclContext *ADC = LCtx->getAnalysisDeclContext(); if (!ADC->getCFGBuildOptions().AddTemporaryDtors) { const MemRegion *Target = Call->getCXXThisVal().getAsRegion(); if (Target && isa<CXXTempObjectRegion>(Target) && Call->getDecl()->getParent()->isAnyDestructorNoReturn()) { // If we've inlined the constructor, then DstEvaluated would be empty. // In this case we still want a sink, which could be implemented // in processCallExit. But we don't have that implemented at the moment, // so if you hit this assertion, see if you can avoid inlining // the respective constructor when analyzer-config cfg-temporary-dtors // is set to false. // Otherwise there's nothing wrong with inlining such constructor. assert(!DstEvaluated.empty() && "We should not have inlined this constructor!"); for (ExplodedNode *N : DstEvaluated) { Bldr.generateSink(CE, N, N->getState()); } // There is no need to run the PostCall and PostStmt checker // callbacks because we just generated sinks on all nodes in th // frontier. return; } } ExplodedNodeSet DstPostArgumentCleanup; for (auto I : DstEvaluated) finishArgumentConstruction(DstPostArgumentCleanup, I, *Call); // If there were other constructors called for object-type arguments // of this constructor, clean them up. ExplodedNodeSet DstPostCall; getCheckerManager().runCheckersForPostCall(DstPostCall, DstPostArgumentCleanup, *Call, *this); getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, CE, *this); }
void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME, ExplodedNode *Pred, ExplodedNodeSet &Dst) { CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<ObjCMethodCall> Msg = CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext()); // Handle the previsits checks. ExplodedNodeSet dstPrevisit; getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred, *Msg, *this); ExplodedNodeSet dstGenericPrevisit; getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit, *Msg, *this); // Proceed with evaluate the message expression. ExplodedNodeSet dstEval; StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currBldrCtx); for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(), DE = dstGenericPrevisit.end(); DI != DE; ++DI) { ExplodedNode *Pred = *DI; ProgramStateRef State = Pred->getState(); CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State); if (UpdatedMsg->isInstanceMessage()) { SVal recVal = UpdatedMsg->getReceiverSVal(); if (!recVal.isUndef()) { // Bifurcate the state into nil and non-nil ones. DefinedOrUnknownSVal receiverVal = recVal.castAs<DefinedOrUnknownSVal>(); ProgramStateRef notNilState, nilState; std::tie(notNilState, nilState) = State->assume(receiverVal); // There are three cases: can be nil or non-nil, must be nil, must be // non-nil. We ignore must be nil, and merge the rest two into non-nil. // FIXME: This ignores many potential bugs (<rdar://problem/11733396>). // Revisit once we have lazier constraints. if (nilState && !notNilState) { continue; } // Check if the "raise" message was sent. assert(notNilState); if (ObjCNoRet.isImplicitNoReturn(ME)) { // If we raise an exception, for now treat it as a sink. // Eventually we will want to handle exceptions properly. Bldr.generateSink(ME, Pred, State); continue; } // Generate a transition to non-Nil state. if (notNilState != State) { Pred = Bldr.generateNode(ME, Pred, notNilState); assert(Pred && "Should have cached out already!"); } } } else { // Check for special class methods that are known to not return // and that we should treat as a sink. if (ObjCNoRet.isImplicitNoReturn(ME)) { // If we raise an exception, for now treat it as a sink. // Eventually we will want to handle exceptions properly. Bldr.generateSink(ME, Pred, Pred->getState()); continue; } } defaultEvalCall(Bldr, Pred, *UpdatedMsg); } ExplodedNodeSet dstPostvisit; getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval, *Msg, *this); // Finally, perform the post-condition check of the ObjCMessageExpr and store // the created nodes in 'Dst'. getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit, *Msg, *this); }
static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt, const LocationContext *LCtx, const RefVal &CurrV, SymbolRef &Sym, const Stmt *S, llvm::raw_string_ostream &os) { CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager(); if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { // Get the name of the callee (if it is available) // from the tracked SVal. SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx); const FunctionDecl *FD = X.getAsFunctionDecl(); // If failed, try to get it from AST. if (!FD) FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl()); if (const auto *MD = dyn_cast<CXXMethodDecl>(CE->getCalleeDecl())) { os << "Call to method '" << MD->getQualifiedNameAsString() << '\''; } else if (FD) { os << "Call to function '" << FD->getQualifiedNameAsString() << '\''; } else { os << "function call"; } } else if (isa<CXXNewExpr>(S)) { os << "Operator 'new'"; } else { assert(isa<ObjCMessageExpr>(S)); CallEventRef<ObjCMethodCall> Call = Mgr.getObjCMethodCall(cast<ObjCMessageExpr>(S), CurrSt, LCtx); switch (Call->getMessageKind()) { case OCM_Message: os << "Method"; break; case OCM_PropertyAccess: os << "Property"; break; case OCM_Subscript: os << "Subscript"; break; } } Optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx); auto Idx = findArgIdxOfSymbol(CurrSt, LCtx, Sym, CE); // If index is not found, we assume that the symbol was returned. if (!Idx) { os << " returns "; } else { os << " writes "; } if (CurrV.getObjKind() == ObjKind::CF) { os << "a Core Foundation object of type '" << Sym->getType().getAsString() << "' with a "; } else if (CurrV.getObjKind() == ObjKind::OS) { os << "an OSObject of type '" << getPrettyTypeName(Sym->getType()) << "' with a "; } else if (CurrV.getObjKind() == ObjKind::Generalized) { os << "an object of type '" << Sym->getType().getAsString() << "' with a "; } else { assert(CurrV.getObjKind() == ObjKind::ObjC); QualType T = Sym->getType(); if (!isa<ObjCObjectPointerType>(T)) { os << "an Objective-C object with a "; } else { const ObjCObjectPointerType *PT = cast<ObjCObjectPointerType>(T); os << "an instance of " << PT->getPointeeType().getAsString() << " with a "; } } if (CurrV.isOwned()) { os << "+1 retain count"; } else { assert(CurrV.isNotOwned()); os << "+0 retain count"; } if (Idx) { os << " into an out parameter '"; const ParmVarDecl *PVD = (*CE)->parameters()[*Idx]; PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(), /*Qualified=*/false); os << "'"; QualType RT = (*CE)->getResultType(); if (!RT.isNull() && !RT->isVoidType()) { SVal RV = (*CE)->getReturnValue(); if (CurrSt->isNull(RV).isConstrainedTrue()) { os << " (assuming the call returns zero)"; } else if (CurrSt->isNonNull(RV).isConstrainedTrue()) { os << " (assuming the call returns non-zero)"; } } } }