diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp @@ -87,6 +87,8 @@ auto R = std::make_unique(NullDereferenceBugType, OS.str(), ErrNode); R->markInteresting(DerefRegion); + const Expr *BugExpr = Call.getOriginExpr(); + bugreporter::trackExpressionValue(ErrNode, BugExpr, *R); C.emitReport(std::move(R)); } diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp --- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp @@ -457,8 +457,22 @@ State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), InnerPointerVal); - // TODO: Add NoteTag, for how the raw pointer got using 'get' method. - C.addTransition(State); + + C.addTransition(State, C.getNoteTag([ThisRegion, InnerPointerVal, + State](PathSensitiveBugReport &BR, + llvm::raw_ostream &OS) { + if (&BR.getBugType() != smartptr::getNullDereferenceBugType() || + !BR.isInteresting(ThisRegion)) + return; + if (!BR.isInteresting(InnerPointerVal) || !BR.isInteresting(InnerPointerVal.getAsSymbol())) + return; + if (ThisRegion->canPrintPretty()) { + OS << "Obtained null inner pointer from"; + checkAndPrettyPrintRegion(OS, ThisRegion); + } else { + OS << "Obtained null inner pointer here"; + } + })); } bool SmartPtrModeling::handleAssignOp(const CallEvent &Call, diff --git a/clang/test/Analysis/smart-ptr-text-output.cpp b/clang/test/Analysis/smart-ptr-text-output.cpp --- a/clang/test/Analysis/smart-ptr-text-output.cpp +++ b/clang/test/Analysis/smart-ptr-text-output.cpp @@ -306,10 +306,44 @@ }; void derefAfterBranchingOnUnknownInnerPtr(std::unique_ptr P) { - A *RP = P.get(); + A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}} if (!RP) { // expected-note {{Assuming 'RP' is null}} // expected-note@-1 {{Taking true branch}} P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} // expected-note@-1{{Dereference of null smart pointer 'P'}} } } + +void getShouldNotAlwaysLeaveANote() { + std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}} + A *a = P.get(); + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} + // expected-note@-1{{Dereference of null smart pointer 'P'}} +} + +void getShouldNotLeaveNoteWhenPtrNotUsed(std::unique_ptr P) { + A *a = P.get(); + if (!P) { // expected-note {{Taking true branch}} + // expected-note@-1 {{Assuming smart pointer 'P' is null}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} + // expected-note@-1{{Dereference of null smart pointer 'P'}} + } +} + +void getShouldLeaveANoteWithWhileLoop(std::unique_ptr P) { + A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}} + while (!RP) { // expected-note {{Assuming 'RP' is null}} + // expected-note@-1 {{Loop condition is true. Entering loop body}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} + // expected-note@-1{{Dereference of null smart pointer 'P'}} + } +} + +void getShouldLeaveANoteWithForLoop(std::unique_ptr P) { + for (A *RP = P.get(); !RP;) { // expected-note {{Assuming 'RP' is null}} + // expected-note@-1 {{Loop condition is true. Entering loop body}} + // expected-note@-2 {{Obtained null inner pointer from 'P'}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} + // expected-note@-1{{Dereference of null smart pointer 'P'}} + } +} \ No newline at end of file