static const char *getArgumentValueString(const CallExpr *CE, CheckerContext &C) { if (CE->getNumArgs() == 0) return "Missing assertion argument"; ExplodedNode *N = C.getPredecessor(); const LocationContext *LC = N->getLocationContext(); ProgramStateRef State = N->getState(); const Expr *Assertion = CE->getArg(0); SVal AssertionVal = State->getSVal(Assertion, LC); if (AssertionVal.isUndef()) return "UNDEFINED"; ProgramStateRef StTrue, StFalse; llvm::tie(StTrue, StFalse) = State->assume(cast<DefinedOrUnknownSVal>(AssertionVal)); if (StTrue) { if (StFalse) return "UNKNOWN"; else return "TRUE"; } else { if (StFalse) return "FALSE"; else llvm_unreachable("Invalid constraint; neither true or false."); } }
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; const ProgramState *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, Pred->getLocationContext()); // We bound the temp obj region to the CXXConstructExpr. Now recover // the lazy compound value when the variable is not a reference. if (AMgr.getLangOptions().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()) { InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, 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 CoreEngine::enqueueEndOfFunction(ExplodedNodeSet &Set) { for (ExplodedNodeSet::iterator I = Set.begin(), E = Set.end(); I != E; ++I) { ExplodedNode *N = *I; // If we are in an inlined call, generate CallExitBegin node. if (N->getLocationContext()->getParent()) { N = generateCallExitBeginNode(N); if (N) WList->enqueue(N); } else { // TODO: We should run remove dead bindings here. G->addEndOfPath(N); NumPathsExplored++; } } }
void ExprInspectionChecker::analyzerEval(const CallExpr *CE, CheckerContext &C) const { ExplodedNode *N = C.getPredecessor(); const LocationContext *LC = N->getLocationContext(); // A specific instantiation of an inlined function may have more constrained // values than can generally be assumed. Skip the check. if (LC->getCurrentStackFrame()->getParent() != 0) return; if (!BT) BT.reset(new BugType("Checking analyzer assumptions", "debug")); BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N); C.emitReport(R); }
/// \brief Run checkers for evaluating a call. /// Only one checker will evaluate the call. void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &Call, ExprEngine &Eng) { const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr()); for (ExplodedNodeSet::iterator NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) { ExplodedNode *Pred = *NI; bool anyEvaluated = false; ExplodedNodeSet checkDst; NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); // Check if any of the EvalCall callbacks can evaluate the call. for (std::vector<EvalCallFunc>::iterator EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end(); EI != EE; ++EI) { ProgramPoint::Kind K = ProgramPoint::PostStmtKind; const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K, Pred->getLocationContext(), EI->Checker); bool evaluated = false; { // CheckerContext generates transitions(populates checkDest) on // destruction, so introduce the scope to make sure it gets properly // populated. CheckerContext C(B, Eng, Pred, L); evaluated = (*EI)(CE, C); } assert(!(evaluated && anyEvaluated) && "There are more than one checkers evaluating the call"); if (evaluated) { anyEvaluated = true; Dst.insert(checkDst); #ifdef NDEBUG break; // on release don't check that no other checker also evals. #endif } } // If none of the checkers evaluated the call, ask ExprEngine to handle it. if (!anyEvaluated) { NodeBuilder B(Pred, Dst, Eng.getBuilderContext()); Eng.defaultEvalCall(B, Pred, Call); } } }
void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const { ExplodedNode *N = C.getPredecessor(); const LocationContext *LC = N->getLocationContext(); // An inlined function could conceivably also be analyzed as a top-level // function. We ignore this case and only emit a message (TRUE or FALSE) // when we are analyzing it as an inlined function. This means that // lfort_analyzer_checkInlined(true) should always print TRUE, but // lfort_analyzer_checkInlined(false) should never actually print anything. if (LC->getCurrentStackFrame()->getParent() == 0) return; if (!BT) BT.reset(new BugType("Checking analyzer assumptions", "debug")); BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N); C.emitReport(R); }
/// \brief Run checkers for end of path. // Note, We do not chain the checker output (like in expandGraphWithCheckers) // for this callback since end of path nodes are expected to be final. void CheckerManager::runCheckersForEndPath(NodeBuilderContext &BC, ExplodedNodeSet &Dst, ExprEngine &Eng) { ExplodedNode *Pred = BC.Pred; // We define the builder outside of the loop bacause if at least one checkers // creates a sucsessor for Pred, we do not need to generate an // autotransition for it. NodeBuilder Bldr(Pred, Dst, BC); for (unsigned i = 0, e = EndPathCheckers.size(); i != e; ++i) { CheckEndPathFunc checkFn = EndPathCheckers[i]; const ProgramPoint &L = BlockEntrance(BC.Block, Pred->getLocationContext(), checkFn.Checker); CheckerContext C(Bldr, Eng, Pred, L); checkFn(C); } }
void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C, bool IsBind) const { // Generate an error node. ExplodedNode *N = C.generateSink(State); if (!N) return; // We know that 'location' cannot be non-null. This is what // we call an "explicit" null dereference. if (!BT_null) BT_null.reset(new BuiltinBug("Dereference of null pointer")); SmallString<100> buf; SmallVector<SourceRange, 2> Ranges; // Walk through lvalue casts to get the original expression // that syntactically caused the load. if (const Expr *expr = dyn_cast<Expr>(S)) S = expr->IgnoreParenLValueCasts(); const MemRegion *sourceR = 0; if (IsBind) { if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) { if (BO->isAssignmentOp()) S = BO->getRHS(); } else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) { assert(DS->isSingleDecl() && "We process decls one by one"); if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) if (const Expr *Init = VD->getAnyInitializer()) S = Init; } } switch (S->getStmtClass()) { case Stmt::ArraySubscriptExprClass: { llvm::raw_svector_ostream os(buf); os << "Array access"; const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S); sourceR = AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), State.getPtr(), N->getLocationContext()); os << " results in a null pointer dereference"; break; } case Stmt::UnaryOperatorClass: { llvm::raw_svector_ostream os(buf); os << "Dereference of null pointer"; const UnaryOperator *U = cast<UnaryOperator>(S); sourceR = AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), State.getPtr(), N->getLocationContext(), true); break; } case Stmt::MemberExprClass: { const MemberExpr *M = cast<MemberExpr>(S); if (M->isArrow()) { llvm::raw_svector_ostream os(buf); os << "Access to field '" << M->getMemberNameInfo() << "' results in a dereference of a null pointer"; sourceR = AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), State.getPtr(), N->getLocationContext(), true); } break; } case Stmt::ObjCIvarRefExprClass: { const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S); if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) { if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { llvm::raw_svector_ostream os(buf); os << "Instance variable access (via '" << VD->getName() << "') results in a null pointer dereference"; } } Ranges.push_back(IV->getSourceRange()); break; } default: break; } BugReport *report = new BugReport(*BT_null, buf.empty() ? BT_null->getDescription() : buf.str(), N); bugreporter::addTrackNullOrUndefValueVisitor(N, bugreporter::GetDerefExpr(N), report); for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I!=E; ++I) report->addRange(*I); if (sourceR) { report->markInteresting(sourceR); report->markInteresting(State->getRawSVal(loc::MemRegionVal(sourceR))); } C.EmitReport(report); }
void ExplodedGraph::reclaimRecentlyAllocatedNodes() { if (!recentlyAllocatedNodes) return; NodeList &nl = *getNodeList(recentlyAllocatedNodes); // Reclaimn all nodes that match *all* the following criteria: // // (1) 1 predecessor (that has one successor) // (2) 1 successor (that has one predecessor) // (3) The ProgramPoint is for a PostStmt. // (4) There is no 'tag' for the ProgramPoint. // (5) The 'store' is the same as the predecessor. // (6) The 'GDM' is the same as the predecessor. // (7) The LocationContext is the same as the predecessor. // (8) The PostStmt is for a non-CFGElement expression. for (NodeList::iterator i = nl.begin(), e = nl.end() ; i != e; ++i) { ExplodedNode *node = *i; // Conditions 1 and 2. if (node->pred_size() != 1 || node->succ_size() != 1) continue; ExplodedNode *pred = *(node->pred_begin()); if (pred->succ_size() != 1) continue; ExplodedNode *succ = *(node->succ_begin()); if (succ->pred_size() != 1) continue; // Condition 3. ProgramPoint progPoint = node->getLocation(); if (!isa<PostStmt>(progPoint)) continue; // Condition 4. PostStmt ps = cast<PostStmt>(progPoint); if (ps.getTag()) continue; if (isa<BinaryOperator>(ps.getStmt())) continue; // Conditions 5, 6, and 7. const ProgramState *state = node->getState(); const ProgramState *pred_state = pred->getState(); if (state->store != pred_state->store || state->GDM != pred_state->GDM || progPoint.getLocationContext() != pred->getLocationContext()) continue; // Condition 8. if (node->getCFG().isBlkExpr(ps.getStmt())) continue; // If we reach here, we can remove the node. This means: // (a) changing the predecessors successor to the successor of this node // (b) changing the successors predecessor to the predecessor of this node // (c) Putting 'node' onto freeNodes. pred->replaceSuccessor(succ); succ->replacePredecessor(pred); if (!freeNodes) freeNodes = new NodeList(); getNodeList(freeNodes)->push_back(node); Nodes.RemoveNode(node); --NumNodes; node->~ExplodedNode(); } nl.clear(); }
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); } } }
void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNodeSet dstPreStmt; getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this); if (CastE->getCastKind() == CK_LValueToRValue) { for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); I!=E; ++I) { ExplodedNode *subExprNode = *I; ProgramStateRef state = subExprNode->getState(); const LocationContext *LCtx = subExprNode->getLocationContext(); evalLoad(Dst, CastE, CastE, subExprNode, state, state->getSVal(Ex, LCtx)); } return; } // All other casts. QualType T = CastE->getType(); QualType ExTy = Ex->getType(); if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE)) T = ExCast->getTypeAsWritten(); StmtNodeBuilder Bldr(dstPreStmt, Dst, *currBldrCtx); for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); I != E; ++I) { Pred = *I; ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); switch (CastE->getCastKind()) { case CK_LValueToRValue: llvm_unreachable("LValueToRValue casts handled earlier."); case CK_ToVoid: continue; // The analyzer doesn't do anything special with these casts, // since it understands retain/release semantics already. case CK_ARCProduceObject: case CK_ARCConsumeObject: case CK_ARCReclaimReturnedObject: case CK_ARCExtendBlockObject: // Fall-through. case CK_CopyAndAutoreleaseBlockObject: // The analyser can ignore atomic casts for now, although some future // checkers may want to make certain that you're not modifying the same // value through atomic and nonatomic pointers. case CK_AtomicToNonAtomic: case CK_NonAtomicToAtomic: // True no-ops. case CK_NoOp: case CK_ConstructorConversion: case CK_UserDefinedConversion: case CK_FunctionToPointerDecay: case CK_BuiltinFnToFnPtr: { // Copy the SVal of Ex to CastE. ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); SVal V = state->getSVal(Ex, LCtx); state = state->BindExpr(CastE, LCtx, V); Bldr.generateNode(CastE, Pred, state); continue; } case CK_MemberPointerToBoolean: // FIXME: For now, member pointers are represented by void *. // FALLTHROUGH case CK_Dependent: case CK_ArrayToPointerDecay: case CK_BitCast: case CK_IntegralCast: case CK_NullToPointer: case CK_IntegralToPointer: case CK_PointerToIntegral: case CK_PointerToBoolean: case CK_IntegralToBoolean: case CK_IntegralToFloating: case CK_FloatingToIntegral: case CK_FloatingToBoolean: case CK_FloatingCast: case CK_FloatingRealToComplex: case CK_FloatingComplexToReal: case CK_FloatingComplexToBoolean: case CK_FloatingComplexCast: case CK_FloatingComplexToIntegralComplex: case CK_IntegralRealToComplex: case CK_IntegralComplexToReal: case CK_IntegralComplexToBoolean: case CK_IntegralComplexCast: case CK_IntegralComplexToFloatingComplex: case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: case CK_ZeroToOCLEvent: { // Delegate to SValBuilder to process. SVal V = state->getSVal(Ex, LCtx); V = svalBuilder.evalCast(V, T, ExTy); state = state->BindExpr(CastE, LCtx, V); Bldr.generateNode(CastE, Pred, state); continue; } case CK_DerivedToBase: case CK_UncheckedDerivedToBase: { // For DerivedToBase cast, delegate to the store manager. SVal val = state->getSVal(Ex, LCtx); val = getStoreManager().evalDerivedToBase(val, CastE); state = state->BindExpr(CastE, LCtx, val); Bldr.generateNode(CastE, Pred, state); continue; } // Handle C++ dyn_cast. case CK_Dynamic: { SVal val = state->getSVal(Ex, LCtx); // Compute the type of the result. QualType resultType = CastE->getType(); if (CastE->isGLValue()) resultType = getContext().getPointerType(resultType); bool Failed = false; // Check if the value being cast evaluates to 0. if (val.isZeroConstant()) Failed = true; // Else, evaluate the cast. else val = getStoreManager().evalDynamicCast(val, T, Failed); if (Failed) { if (T->isReferenceType()) { // A bad_cast exception is thrown if input value is a reference. // Currently, we model this, by generating a sink. Bldr.generateSink(CastE, Pred, state); continue; } else { // If the cast fails on a pointer, bind to 0. state = state->BindExpr(CastE, LCtx, svalBuilder.makeNull()); } } else { // If we don't know if the cast succeeded, conjure a new symbol. if (val.isUnknown()) { DefinedOrUnknownSVal NewSym = svalBuilder.conjureSymbolVal(0, CastE, LCtx, resultType, currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, NewSym); } else // Else, bind to the derived region value. state = state->BindExpr(CastE, LCtx, val); } Bldr.generateNode(CastE, Pred, state); continue; } case CK_NullToMemberPointer: { // FIXME: For now, member pointers are represented by void *. SVal V = svalBuilder.makeIntValWithPtrWidth(0, true); state = state->BindExpr(CastE, LCtx, V); Bldr.generateNode(CastE, Pred, state); continue; } // Various C++ casts that are not handled yet. case CK_ToUnion: case CK_BaseToDerived: case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: case CK_ReinterpretMemberPointer: case CK_VectorSplat: case CK_LValueBitCast: { // Recover some path-sensitivty by conjuring a new value. QualType resultType = CastE->getType(); if (CastE->isGLValue()) resultType = getContext().getPointerType(resultType); SVal result = svalBuilder.conjureSymbolVal(0, CastE, LCtx, resultType, currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, result); Bldr.generateNode(CastE, Pred, state); continue; } } } }
/// \brief Run checkers for evaluating a call. /// Only one checker will evaluate the call. void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallExpr *CE, ExprEngine &Eng, GraphExpander *defaultEval) { if (EvalCallCheckers.empty() && InlineCallCheckers.empty() && defaultEval == 0) { Dst.insert(Src); return; } for (ExplodedNodeSet::iterator NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) { ExplodedNode *Pred = *NI; bool anyEvaluated = false; // First, check if any of the InlineCall callbacks can evaluate the call. assert(InlineCallCheckers.size() <= 1 && "InlineCall is a special hacky callback to allow intrusive" "evaluation of the call (which simulates inlining). It is " "currently only used by OSAtomicChecker and should go away " "at some point."); for (std::vector<InlineCallFunc>::iterator EI = InlineCallCheckers.begin(), EE = InlineCallCheckers.end(); EI != EE; ++EI) { ExplodedNodeSet checkDst; bool evaluated = (*EI)(CE, Eng, Pred, checkDst); assert(!(evaluated && anyEvaluated) && "There are more than one checkers evaluating the call"); if (evaluated) { anyEvaluated = true; Dst.insert(checkDst); #ifdef NDEBUG break; // on release don't check that no other checker also evals. #endif } } #ifdef NDEBUG // on release don't check that no other checker also evals. if (anyEvaluated) { break; } #endif // Next, check if any of the EvalCall callbacks can evaluate the call. for (std::vector<EvalCallFunc>::iterator EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end(); EI != EE; ++EI) { ExplodedNodeSet checkDst; ProgramPoint::Kind K = ProgramPoint::PostStmtKind; const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K, Pred->getLocationContext(), EI->Checker); bool evaluated = false; { // CheckerContext generates transitions(populates checkDest) on // destruction, so introduce the scope to make sure it gets properly // populated. CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, L, 0); evaluated = (*EI)(CE, C); } assert(!(evaluated && anyEvaluated) && "There are more than one checkers evaluating the call"); if (evaluated) { anyEvaluated = true; Dst.insert(checkDst); #ifdef NDEBUG break; // on release don't check that no other checker also evals. #endif } } // If none of the checkers evaluated the call, ask ExprEngine to handle it. if (!anyEvaluated) { if (defaultEval) defaultEval->expandGraph(Dst, Pred); else Dst.insert(Pred); } } }
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, const MemRegion *Dest, ExplodedNode *Pred, ExplodedNodeSet &destNodes) { const CXXConstructorDecl *CD = E->getConstructor(); assert(CD); #if 0 if (!(CD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall())) // FIXME: invalidate the object. return; #endif // Evaluate other arguments. ExplodedNodeSet argsEvaluated; const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>(); evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated); #if 0 // Is the constructor elidable? if (E->isElidable()) { VisitAggExpr(E->getArg(0), destNodes, Pred, Dst); // FIXME: this is here to force propagation if VisitAggExpr doesn't if (destNodes.empty()) destNodes.Add(Pred); return; } #endif // Perform the previsit of the constructor. ExplodedNodeSet destPreVisit; getCheckerManager().runCheckersForPreStmt(destPreVisit, argsEvaluated, E, *this); // Evaluate the constructor. Currently we don't now allow checker-specific // implementations of specific constructors (as we do with ordinary // function calls. We can re-evaluate this in the future. #if 0 // Inlining currently isn't fully implemented. if (AMgr.shouldInlineCall()) { if (!Dest) Dest = svalBuilder.getRegionManager().getCXXTempObjectRegion(E, Pred->getLocationContext()); // The callee stack frame context used to create the 'this' // parameter region. const StackFrameContext *SFC = AMgr.getStackFrame(CD, Pred->getLocationContext(), E, currentBuilderContext->getBlock(), currentStmtIdx); // Create the 'this' region. const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor()->getParent(), SFC); CallEnter Loc(E, SFC, Pred->getLocationContext()); StmtNodeBuilder Bldr(argsEvaluated, destNodes, *currentBuilderContext); for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(), NE = argsEvaluated.end(); NI != NE; ++NI) { const ProgramState *state = (*NI)->getState(); // Setup 'this' region, so that the ctor is evaluated on the object pointed // by 'Dest'. state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); Bldr.generateNode(Loc, *NI, state); } } #endif // Default semantics: invalidate all regions passed as arguments. ExplodedNodeSet destCall; { StmtNodeBuilder Bldr(destPreVisit, destCall, *currentBuilderContext); for (ExplodedNodeSet::iterator i = destPreVisit.begin(), e = destPreVisit.end(); i != e; ++i) { ExplodedNode *Pred = *i; const LocationContext *LC = Pred->getLocationContext(); const ProgramState *state = Pred->getState(); state = invalidateArguments(state, CallOrObjCMessage(E, state, LC), LC); Bldr.generateNode(E, Pred, state); } } // Do the post visit. getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this); }
void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNodeSet dstPreStmt; getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this); if (CastE->getCastKind() == CK_LValueToRValue) { for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); I!=E; ++I) { ExplodedNode *subExprNode = *I; const ProgramState *state = subExprNode->getState(); const LocationContext *LCtx = subExprNode->getLocationContext(); evalLoad(Dst, CastE, subExprNode, state, state->getSVal(Ex, LCtx)); } return; } // All other casts. QualType T = CastE->getType(); QualType ExTy = Ex->getType(); if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE)) T = ExCast->getTypeAsWritten(); StmtNodeBuilder Bldr(dstPreStmt, Dst, *currentBuilderContext); for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); I != E; ++I) { Pred = *I; switch (CastE->getCastKind()) { case CK_LValueToRValue: llvm_unreachable("LValueToRValue casts handled earlier."); case CK_ToVoid: continue; // The analyzer doesn't do anything special with these casts, // since it understands retain/release semantics already. case CK_ARCProduceObject: case CK_ARCConsumeObject: case CK_ARCReclaimReturnedObject: case CK_ARCExtendBlockObject: // Fall-through. // The analyser can ignore atomic casts for now, although some future // checkers may want to make certain that you're not modifying the same // value through atomic and nonatomic pointers. case CK_AtomicToNonAtomic: case CK_NonAtomicToAtomic: // True no-ops. case CK_NoOp: case CK_FunctionToPointerDecay: { // Copy the SVal of Ex to CastE. const ProgramState *state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); SVal V = state->getSVal(Ex, LCtx); state = state->BindExpr(CastE, LCtx, V); Bldr.generateNode(CastE, Pred, state); continue; } case CK_Dependent: case CK_ArrayToPointerDecay: case CK_BitCast: case CK_LValueBitCast: case CK_IntegralCast: case CK_NullToPointer: case CK_IntegralToPointer: case CK_PointerToIntegral: case CK_PointerToBoolean: case CK_IntegralToBoolean: case CK_IntegralToFloating: case CK_FloatingToIntegral: case CK_FloatingToBoolean: case CK_FloatingCast: case CK_FloatingRealToComplex: case CK_FloatingComplexToReal: case CK_FloatingComplexToBoolean: case CK_FloatingComplexCast: case CK_FloatingComplexToIntegralComplex: case CK_IntegralRealToComplex: case CK_IntegralComplexToReal: case CK_IntegralComplexToBoolean: case CK_IntegralComplexCast: case CK_IntegralComplexToFloatingComplex: case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: { // Delegate to SValBuilder to process. const ProgramState *state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); SVal V = state->getSVal(Ex, LCtx); V = svalBuilder.evalCast(V, T, ExTy); state = state->BindExpr(CastE, LCtx, V); Bldr.generateNode(CastE, Pred, state); continue; } case CK_DerivedToBase: case CK_UncheckedDerivedToBase: { // For DerivedToBase cast, delegate to the store manager. const ProgramState *state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); SVal val = state->getSVal(Ex, LCtx); val = getStoreManager().evalDerivedToBase(val, T); state = state->BindExpr(CastE, LCtx, val); Bldr.generateNode(CastE, Pred, state); continue; } // Various C++ casts that are not handled yet. case CK_Dynamic: case CK_ToUnion: case CK_BaseToDerived: case CK_NullToMemberPointer: case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: case CK_UserDefinedConversion: case CK_ConstructorConversion: case CK_VectorSplat: case CK_MemberPointerToBoolean: { // Recover some path-sensitivty by conjuring a new value. QualType resultType = CastE->getType(); if (CastE->isLValue()) resultType = getContext().getPointerType(resultType); SVal result = svalBuilder.getConjuredSymbolVal(NULL, CastE, resultType, currentBuilderContext->getCurrentBlockCount()); const LocationContext *LCtx = Pred->getLocationContext(); const ProgramState *state = Pred->getState()->BindExpr(CastE, LCtx, result); Bldr.generateNode(CastE, Pred, state); continue; } } } }
void UninitializedObjectChecker::checkEndFunction( const ReturnStmt *RS, CheckerContext &Context) const { const auto *CtorDecl = dyn_cast_or_null<CXXConstructorDecl>( Context.getLocationContext()->getDecl()); if (!CtorDecl) return; if (!CtorDecl->isUserProvided()) return; if (CtorDecl->getParent()->isUnion()) return; // This avoids essentially the same error being reported multiple times. if (willObjectBeAnalyzedLater(CtorDecl, Context)) return; Optional<nonloc::LazyCompoundVal> Object = getObjectVal(CtorDecl, Context); if (!Object) return; FindUninitializedFields F(Context.getState(), Object->getRegion(), CheckPointeeInitialization); const UninitFieldMap &UninitFields = F.getUninitFields(); if (UninitFields.empty()) return; // In non-pedantic mode, if Object's region doesn't contain a single // initialized field, we'll assume that Object was intentionally left // uninitialized. if (!IsPedantic && !F.isAnyFieldInitialized()) return; // There are uninitialized fields in the record. ExplodedNode *Node = Context.generateNonFatalErrorNode(Context.getState()); if (!Node) return; PathDiagnosticLocation LocUsedForUniqueing; const Stmt *CallSite = Context.getStackFrame()->getCallSite(); if (CallSite) LocUsedForUniqueing = PathDiagnosticLocation::createBegin( CallSite, Context.getSourceManager(), Node->getLocationContext()); // For Plist consumers that don't support notes just yet, we'll convert notes // to warnings. if (ShouldConvertNotesToWarnings) { for (const auto &Pair : UninitFields) { auto Report = llvm::make_unique<BugReport>( *BT_uninitField, Pair.second, Node, LocUsedForUniqueing, Node->getLocationContext()->getDecl()); Context.emitReport(std::move(Report)); } return; } SmallString<100> WarningBuf; llvm::raw_svector_ostream WarningOS(WarningBuf); WarningOS << UninitFields.size() << " uninitialized field" << (UninitFields.size() == 1 ? "" : "s") << " at the end of the constructor call"; auto Report = llvm::make_unique<BugReport>( *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing, Node->getLocationContext()->getDecl()); for (const auto &Pair : UninitFields) { Report->addNote(Pair.second, PathDiagnosticLocation::create(Pair.first->getDecl(), Context.getSourceManager())); } Context.emitReport(std::move(Report)); }