diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index e7295878fa6f..1dbd8f0379e6 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -296,6 +296,49 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, return NULL; } +namespace { +class ReturnNullVisitor : public BugReporterVisitorImpl { + 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(ReturnNode->getLocation()); + const ReturnStmt *Ret = cast(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(RetE)) + if (const DeclaratorDecl *DD = dyn_cast(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(&pp)) { if (ps->getStmt() == S) break; + } else if (const CallExitEnd *CEE = dyn_cast(&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(PP = N->getLocation())) + N = N->getFirstPred(); + + if (N && isa(PP)) { + // Find a ReturnStmt, if there is one. + do { + N = N->getFirstPred(); + PP = N->getLocation(); + } while (!isa(PP) && !isa(PP)); + + if (const StmtPoint *SP = dyn_cast(&PP)) { + if (const ReturnStmt *Ret = SP->getStmtAs()) { + if (const Expr *RetE = Ret->getRetValue()) { + report->addVisitor(new ReturnNullVisitor(N)); + addTrackNullOrUndefValueVisitor(N, RetE, report); + } + } + } + } } } diff --git a/clang/test/Analysis/inlining/path-notes.c b/clang/test/Analysis/inlining/path-notes.c index bd239152eb20..66a2f270df38 100644 --- a/clang/test/Analysis/inlining/path-notes.c +++ b/clang/test/Analysis/inlining/path-notes.c @@ -57,6 +57,38 @@ void testStoreCheck(int *a) { } +int *getZero() { + int *p = 0; + // expected-note@-1 {{Variable 'p' initialized to a null pointer value}} + // ^ This note checks that we add a second visitor for the return value. + return p; + // expected-note@-1 {{Returning null pointer (loaded from 'p')}} +} + +void testReturnZero() { + *getZero() = 1; // expected-warning{{Dereference of null pointer}} + // expected-note@-1 {{Calling 'getZero'}} + // expected-note@-2 {{Returning from 'getZero'}} + // expected-note@-3 {{Dereference of null pointer}} +} + +void testInitZero() { + // FIXME: Diagnostics: Need to step into the function whose result is assigned to an interesting region + int *a = getZero(); + // expected-note@-1 {{Variable 'a' initialized to a null pointer value}} + *a = 1; // expected-warning{{Dereference of null pointer}} + // expected-note@-1 {{Dereference of null pointer (loaded from variable 'a')}} +} + +void testStoreZero(int *a) { + // FIXME: Diagnostics: Need to step into the function whose result is assigned to an interesting region + a = getZero(); + // expected-note@-1 {{Null pointer value stored to 'a'}} + *a = 1; // expected-warning{{Dereference of null pointer}} + // expected-note@-1 {{Dereference of null pointer (loaded from variable 'a')}} +} + + // CHECK: // CHECK: // CHECK: @@ -1286,6 +1318,774 @@ void testStoreCheck(int *a) { // CHECK: file0 // CHECK: // CHECK: +// CHECK: +// CHECK: path +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col4 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col10 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line69 +// CHECK: col4 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col4 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col12 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: depth0 +// CHECK: extended_message +// CHECK: Calling 'getZero' +// CHECK: message +// CHECK: Calling 'getZero' +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line60 +// CHECK: col1 +// CHECK: file0 +// CHECK: +// CHECK: depth1 +// CHECK: extended_message +// CHECK: Entered call from 'testReturnZero' +// CHECK: message +// CHECK: Entered call from 'testReturnZero' +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line60 +// CHECK: col1 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line60 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line61 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line61 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line61 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line61 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line61 +// CHECK: col8 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: depth1 +// CHECK: extended_message +// CHECK: Variable 'p' initialized to a null pointer value +// CHECK: message +// CHECK: Variable 'p' initialized to a null pointer value +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line61 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line61 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line64 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line64 +// CHECK: col8 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line64 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line64 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line64 +// CHECK: col10 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: depth1 +// CHECK: extended_message +// CHECK: Returning null pointer (loaded from 'p') +// CHECK: message +// CHECK: Returning null pointer (loaded from 'p') +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line69 +// CHECK: col4 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col4 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col12 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: depth1 +// CHECK: extended_message +// CHECK: Returning from 'getZero' +// CHECK: message +// CHECK: Returning from 'getZero' +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col4 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col10 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col4 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col10 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line69 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line69 +// CHECK: col16 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: depth0 +// CHECK: extended_message +// CHECK: Dereference of null pointer +// CHECK: message +// CHECK: Dereference of null pointer +// CHECK: +// CHECK: +// CHECK: descriptionDereference of null pointer +// CHECK: categoryLogic error +// CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttestReturnZero +// CHECK: issue_hash1 +// CHECK: location +// CHECK: +// CHECK: line69 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: path +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col12 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col18 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col12 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col18 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col12 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col18 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line77 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col8 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: depth0 +// CHECK: extended_message +// CHECK: Variable 'a' initialized to a null pointer value +// CHECK: message +// CHECK: Variable 'a' initialized to a null pointer value +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line77 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line79 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line79 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line79 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line79 +// CHECK: col4 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line79 +// CHECK: col4 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: depth0 +// CHECK: extended_message +// CHECK: Dereference of null pointer (loaded from variable 'a') +// CHECK: message +// CHECK: Dereference of null pointer (loaded from variable 'a') +// CHECK: +// CHECK: +// CHECK: descriptionDereference of null pointer (loaded from variable 'a') +// CHECK: categoryLogic error +// CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttestInitZero +// CHECK: issue_hash4 +// CHECK: location +// CHECK: +// CHECK: line79 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: path +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col13 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col13 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col13 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line85 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col15 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: depth0 +// CHECK: extended_message +// CHECK: Null pointer value stored to 'a' +// CHECK: message +// CHECK: Null pointer value stored to 'a' +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line85 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line87 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line87 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line87 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line87 +// CHECK: col4 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line87 +// CHECK: col4 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: depth0 +// CHECK: extended_message +// CHECK: Dereference of null pointer (loaded from variable 'a') +// CHECK: message +// CHECK: Dereference of null pointer (loaded from variable 'a') +// CHECK: +// CHECK: +// CHECK: descriptionDereference of null pointer (loaded from variable 'a') +// CHECK: categoryLogic error +// CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttestStoreZero +// CHECK: issue_hash4 +// CHECK: location +// CHECK: +// CHECK: line87 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: // CHECK: // CHECK: // CHECK: