diff options
author | Jordan Rose <jordan_rose@apple.com> | 2012-08-24 16:34:31 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2012-08-24 16:34:31 +0000 |
commit | 23df2437a47ff129d2923ae325d42e79682a7f14 (patch) | |
tree | d896ec1610759060b1765214210c9d80566764fc /lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | |
parent | 8a30e7735a5c2b8b105734fc9b131cc43c56d765 (diff) |
[analyzer] If we dereference a NULL that came from a function, show the return.
More generally, any time we try to track where a null value came from, we
should show if it came from a function. This usually isn't necessary if
the value is symbolic, but if the value is just a constant we previously
just ignored its origin entirely. Now, we'll step into the function and
recursively add a visitor to the returned expression.
<rdar://problem/12114609>
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162563 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/BugReporterVisitors.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index e7295878fa..1dbd8f0379 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -296,6 +296,49 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, return NULL; } +namespace { +class ReturnNullVisitor : public BugReporterVisitorImpl<ReturnNullVisitor> { + const ExplodedNode *ReturnNode; +public: + ReturnNullVisitor(const ExplodedNode *N) : ReturnNode(N) {} + + virtual void Profile(llvm::FoldingSetNodeID &ID) const { + static int Tag = 0; + ID.AddPointer(&Tag); + ID.Add(*ReturnNode); + } + + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) { + if (ReturnNode != BRC.getNodeResolver().getOriginalNode(N)) + return 0; + + StmtPoint SP = cast<StmtPoint>(ReturnNode->getLocation()); + const ReturnStmt *Ret = cast<ReturnStmt>(SP.getStmt()); + PathDiagnosticLocation L(Ret, BRC.getSourceManager(), + N->getLocationContext()); + + SmallString<64> Msg; + llvm::raw_svector_ostream Out(Msg); + + if (Loc::isLocType(Ret->getRetValue()->getType())) + Out << "Returning null pointer"; + else + Out << "Returning zero"; + + // FIXME: We should have a more generalized printing mechanism. + const Expr *RetE = Ret->getRetValue()->IgnoreParenCasts(); + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE)) + if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl())) + Out << " (loaded from '" << *DD << "')"; + + return new PathDiagnosticEventPiece(L, Out.str()); + } +}; +} // end anonymous namespace + void bugreporter::addTrackNullOrUndefValueVisitor(const ExplodedNode *N, const Stmt *S, BugReport *report) { @@ -311,6 +354,9 @@ void bugreporter::addTrackNullOrUndefValueVisitor(const ExplodedNode *N, 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(); } @@ -364,6 +410,28 @@ void bugreporter::addTrackNullOrUndefValueVisitor(const ExplodedNode *N, report->addVisitor(new TrackConstraintBRVisitor(loc::MemRegionVal(R), false)); } + } else { + // Walk backwards to just before the post-statement checks. + ProgramPoint PP = N->getLocation(); + while (N && isa<PostStmt>(PP = N->getLocation())) + N = N->getFirstPred(); + + if (N && isa<CallExitEnd>(PP)) { + // Find a ReturnStmt, if there is one. + do { + N = N->getFirstPred(); + PP = N->getLocation(); + } while (!isa<StmtPoint>(PP) && !isa<CallEnter>(PP)); + + if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) { + if (const ReturnStmt *Ret = SP->getStmtAs<ReturnStmt>()) { + if (const Expr *RetE = Ret->getRetValue()) { + report->addVisitor(new ReturnNullVisitor(N)); + addTrackNullOrUndefValueVisitor(N, RetE, report); + } + } + } + } } } |