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); }
bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &report, bool IsArg) { if (!S || !N) return false; if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) S = OVE->getSourceExpr(); if (IsArg) { assert(isa<CallEnter>(N->getLocation()) && "Tracking arg but not at call"); } else { // Walk through nodes until we get one that matches the statement exactly. do { const ProgramPoint &pp = N->getLocation(); if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) { if (ps->getStmt() == S) break; } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) { if (CEE->getCalleeContext()->getCallSite() == S) break; } N = N->getFirstPred(); } while (N); if (!N) return false; } ProgramStateRef state = N->getState(); // See if the expression we're interested refers to a variable. // If so, we can track both its contents and constraints on its value. if (const Expr *Ex = dyn_cast<Expr>(S)) { // Strip off parens and casts. Note that this will never have issues with // C++ user-defined implicit conversions, because those have a constructor // or function call inside. Ex = Ex->IgnoreParenCasts(); if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) { // FIXME: Right now we only track VarDecls because it's non-trivial to // get a MemRegion for any other DeclRefExprs. <rdar://problem/12114812> if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { ProgramStateManager &StateMgr = state->getStateManager(); MemRegionManager &MRMgr = StateMgr.getRegionManager(); const VarRegion *R = MRMgr.getVarRegion(VD, N->getLocationContext()); // Mark both the variable region and its contents as interesting. SVal V = state->getRawSVal(loc::MemRegionVal(R)); // If the value matches the default for the variable region, that // might mean that it's been cleared out of the state. Fall back to // the full argument expression (with casts and such intact). if (IsArg) { bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant(); if (!UseArgValue) { const SymbolRegionValue *SRV = dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol()); if (SRV) UseArgValue = (SRV->getRegion() == R); } if (UseArgValue) V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); } report.markInteresting(R); report.markInteresting(V); report.addVisitor(new UndefOrNullArgVisitor(R)); // If the contents are symbolic, find out when they became null. if (V.getAsLocSymbol()) { BugReporterVisitor *ConstraintTracker = new TrackConstraintBRVisitor(cast<DefinedSVal>(V), false); report.addVisitor(ConstraintTracker); } report.addVisitor(new FindLastStoreBRVisitor(V, R)); return true; } } } // If the expression does NOT refer to a variable, we can still track // constraints on its contents. SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); // Uncomment this to find cases where we aren't properly getting the // base value that was dereferenced. // assert(!V.isUnknownOrUndef()); // Is it a symbolic value? if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) { // At this point we are dealing with the region's LValue. // However, if the rvalue is a symbolic region, we should track it as well. SVal RVal = state->getSVal(L->getRegion()); const MemRegion *RegionRVal = RVal.getAsRegion(); report.addVisitor(new UndefOrNullArgVisitor(L->getRegion())); if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) { report.markInteresting(RegionRVal); report.addVisitor(new TrackConstraintBRVisitor( loc::MemRegionVal(RegionRVal), false)); } } else { // Otherwise, if the value came from an inlined function call, // we should at least make sure that function isn't pruned in our output. if (const Expr *E = dyn_cast<Expr>(S)) S = E->IgnoreParenCasts(); ReturnVisitor::addVisitorIfNecessary(N, S, report); } return true; }
bool bugreporter::trackNullOrUndefValue(const ExplodedNode *ErrorNode, const Stmt *S, BugReport &report, bool IsArg) { if (!S || !ErrorNode) return false; if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) S = OVE->getSourceExpr(); const ExplodedNode *N = ErrorNode; const Expr *Inner = 0; if (const Expr *Ex = dyn_cast<Expr>(S)) { Ex = Ex->IgnoreParenCasts(); if (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex)) Inner = Ex; } if (IsArg) { assert(N->getLocation().getAs<CallEnter>() && "Tracking arg but not at call"); } else { // Walk through nodes until we get one that matches the statement exactly. // Alternately, if we hit a known lvalue for the statement, we know we've // gone too far (though we can likely track the lvalue better anyway). do { const ProgramPoint &pp = N->getLocation(); if (Optional<PostStmt> ps = pp.getAs<PostStmt>()) { if (ps->getStmt() == S || ps->getStmt() == Inner) break; } else if (Optional<CallExitEnd> CEE = pp.getAs<CallExitEnd>()) { if (CEE->getCalleeContext()->getCallSite() == S || CEE->getCalleeContext()->getCallSite() == Inner) break; } N = N->getFirstPred(); } while (N); if (!N) return false; } ProgramStateRef state = N->getState(); // See if the expression we're interested refers to a variable. // If so, we can track both its contents and constraints on its value. if (Inner && ExplodedGraph::isInterestingLValueExpr(Inner)) { const MemRegion *R = 0; // First check if this is a DeclRefExpr for a C++ reference type. // For those, we want the location of the reference. if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Inner)) { if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { if (VD->getType()->isReferenceType()) { ProgramStateManager &StateMgr = state->getStateManager(); MemRegionManager &MRMgr = StateMgr.getRegionManager(); R = MRMgr.getVarRegion(VD, N->getLocationContext()); } } } // For all other cases, find the location by scouring the ExplodedGraph. if (!R) { // Find the ExplodedNode where the lvalue (the value of 'Ex') // was computed. We need this for getting the location value. const ExplodedNode *LVNode = N; while (LVNode) { if (Optional<PostStmt> P = LVNode->getLocation().getAs<PostStmt>()) { if (P->getStmt() == Inner) break; } LVNode = LVNode->getFirstPred(); } assert(LVNode && "Unable to find the lvalue node."); ProgramStateRef LVState = LVNode->getState(); R = LVState->getSVal(Inner, LVNode->getLocationContext()).getAsRegion(); } if (R) { // Mark both the variable region and its contents as interesting. SVal V = state->getRawSVal(loc::MemRegionVal(R)); // If the value matches the default for the variable region, that // might mean that it's been cleared out of the state. Fall back to // the full argument expression (with casts and such intact). if (IsArg) { bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant(); if (!UseArgValue) { const SymbolRegionValue *SRV = dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol()); if (SRV) UseArgValue = (SRV->getRegion() == R); } if (UseArgValue) V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); } report.markInteresting(R); report.markInteresting(V); report.addVisitor(new UndefOrNullArgVisitor(R)); if (isa<SymbolicRegion>(R)) { TrackConstraintBRVisitor *VI = new TrackConstraintBRVisitor(loc::MemRegionVal(R), false); report.addVisitor(VI); } // If the contents are symbolic, find out when they became null. if (V.getAsLocSymbol()) { BugReporterVisitor *ConstraintTracker = new TrackConstraintBRVisitor(V.castAs<DefinedSVal>(), false); report.addVisitor(ConstraintTracker); // Add visitor, which will suppress inline defensive checks. if (ErrorNode->getState()->isNull(V).isConstrainedTrue()) { BugReporterVisitor *IDCSuppressor = new SuppressInlineDefensiveChecksVisitor(V.castAs<DefinedSVal>(), ErrorNode); report.addVisitor(IDCSuppressor); } } if (Optional<KnownSVal> KV = V.getAs<KnownSVal>()) report.addVisitor(new FindLastStoreBRVisitor(*KV, R)); return true; } } // If the expression is not an "lvalue expression", we can still // track the constraints on its contents. SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); // If the value came from an inlined function call, we should at least make // sure that function isn't pruned in our output. if (const Expr *E = dyn_cast<Expr>(S)) S = E->IgnoreParenCasts(); ReturnVisitor::addVisitorIfNecessary(N, S, report); // Uncomment this to find cases where we aren't properly getting the // base value that was dereferenced. // assert(!V.isUnknownOrUndef()); // Is it a symbolic value? if (Optional<loc::MemRegionVal> L = V.getAs<loc::MemRegionVal>()) { // At this point we are dealing with the region's LValue. // However, if the rvalue is a symbolic region, we should track it as well. SVal RVal = state->getSVal(L->getRegion()); const MemRegion *RegionRVal = RVal.getAsRegion(); report.addVisitor(new UndefOrNullArgVisitor(L->getRegion())); if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) { report.markInteresting(RegionRVal); report.addVisitor(new TrackConstraintBRVisitor( loc::MemRegionVal(RegionRVal), false)); } } return true; }
void bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &report) { if (!S || !N) return; ProgramStateManager &StateMgr = N->getState()->getStateManager(); // Walk through nodes until we get one that matches the statement exactly. while (N) { const ProgramPoint &pp = N->getLocation(); if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) { if (ps->getStmt() == S) break; } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) { if (CEE->getCalleeContext()->getCallSite() == S) break; } N = N->getFirstPred(); } if (!N) return; ProgramStateRef state = N->getState(); // See if the expression we're interested refers to a variable. // If so, we can track both its contents and constraints on its value. if (const Expr *Ex = dyn_cast<Expr>(S)) { // Strip off parens and casts. Note that this will never have issues with // C++ user-defined implicit conversions, because those have a constructor // or function call inside. Ex = Ex->IgnoreParenCasts(); if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) { // FIXME: Right now we only track VarDecls because it's non-trivial to // get a MemRegion for any other DeclRefExprs. <rdar://problem/12114812> if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { const VarRegion *R = StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); // Mark both the variable region and its contents as interesting. SVal V = state->getRawSVal(loc::MemRegionVal(R)); report.markInteresting(R); report.markInteresting(V); // If the contents are symbolic, find out when they became null. if (V.getAsLocSymbol()) { BugReporterVisitor *ConstraintTracker = new TrackConstraintBRVisitor(cast<loc::MemRegionVal>(V), false); report.addVisitor(ConstraintTracker); } report.addVisitor(new FindLastStoreBRVisitor(V, R)); return; } } } // If the expression does NOT refer to a variable, we can still track // constraints on its contents. SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); // Uncomment this to find cases where we aren't properly getting the // base value that was dereferenced. // assert(!V.isUnknownOrUndef()); // Is it a symbolic value? if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) { const MemRegion *Base = L->getRegion()->getBaseRegion(); if (isa<SymbolicRegion>(Base)) { report.markInteresting(Base); report.addVisitor(new TrackConstraintBRVisitor(loc::MemRegionVal(Base), false)); } } else { // Otherwise, if the value came from an inlined function call, // we should at least make sure that function isn't pruned in our output. ReturnVisitor::addVisitorIfNecessary(N, S, report); } }