diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -301,6 +301,26 @@ IsPrunable); } + /// A shorthand version of getNoteTag that accepts a lambda with stream for + /// note. + /// + /// @param Cb Callback with 'BugReport &' and 'llvm::raw_ostream &'. + /// @param IsPrunable Whether the note is prunable. It allows BugReporter + /// to omit the note from the report if it would make the displayed + /// bug path significantly shorter. + const NoteTag *getNoteTag( + std::function &&Cb, + bool IsPrunable = false) { + return getNoteTag( + [Cb](PathSensitiveBugReport &BR) -> std::string { + llvm::SmallString<128> Str; + llvm::raw_svector_ostream OS(Str); + Cb(BR, OS); + return std::string(OS.str()); + }, + IsPrunable); + } + /// Returns the word that should be used to refer to the declaration /// in the report. StringRef getDeclDescription(const Decl *D); diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtr.h b/clang/lib/StaticAnalyzer/Checkers/SmartPtr.h --- a/clang/lib/StaticAnalyzer/Checkers/SmartPtr.h +++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtr.h @@ -26,6 +26,8 @@ /// Returns whether the smart pointer is null or not. bool isNullSmartPtr(const ProgramStateRef State, const MemRegion *ThisRegion); +const BugType *getNullDereferenceBugType(); + } // namespace smartptr } // namespace ento } // namespace clang 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 @@ -23,23 +23,40 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" +#include "llvm/ADT/StringRef.h" using namespace clang; using namespace ento; namespace { -class SmartPtrChecker : public Checker { - BugType NullDereferenceBugType{this, "Null SmartPtr dereference", - "C++ Smart Pointer"}; +static const BugType *NullDereferenceBugTypePtr; + +class SmartPtrChecker : public Checker { public: void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + BugType NullDereferenceBugType{this, "Null SmartPtr dereference", + "C++ Smart Pointer"}; private: - void reportBug(CheckerContext &C, const CallEvent &Call) const; + void reportBug(CheckerContext &C, const MemRegion *DerefRegion, + const CallEvent &Call) const; + void explainDereference(llvm::raw_ostream &OS, const MemRegion *DerefRegion, + const CallEvent &Call) const; }; } // end of anonymous namespace +// Define the inter-checker API. +namespace clang { +namespace ento { +namespace smartptr { + +const BugType *getNullDereferenceBugType() { return NullDereferenceBugTypePtr; } + +} // namespace smartptr +} // namespace ento +} // namespace clang + void SmartPtrChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { if (!smartptr::isStdSmartPtrCall(Call)) @@ -55,23 +72,34 @@ OverloadedOperatorKind OOK = OC->getOverloadedOperator(); if (OOK == OO_Star || OOK == OO_Arrow) { if (smartptr::isNullSmartPtr(State, ThisRegion)) - reportBug(C, Call); + reportBug(C, ThisRegion, Call); } } -void SmartPtrChecker::reportBug(CheckerContext &C, +void SmartPtrChecker::reportBug(CheckerContext &C, const MemRegion *DerefRegion, const CallEvent &Call) const { ExplodedNode *ErrNode = C.generateErrorNode(); if (!ErrNode) return; - - auto R = std::make_unique( - NullDereferenceBugType, "Dereference of null smart pointer", ErrNode); + llvm::SmallString<128> Str; + llvm::raw_svector_ostream OS(Str); + explainDereference(OS, DerefRegion, Call); + auto R = std::make_unique(NullDereferenceBugType, + OS.str(), ErrNode); + R->markInteresting(DerefRegion); C.emitReport(std::move(R)); } +void SmartPtrChecker::explainDereference(llvm::raw_ostream &OS, + const MemRegion *DerefRegion, + const CallEvent &Call) const { + OS << "Dereference of null smart pointer "; + DerefRegion->printPretty(OS); +} + void ento::registerSmartPtrChecker(CheckerManager &Mgr) { - Mgr.registerChecker(); + SmartPtrChecker *Checker = Mgr.registerChecker(); + NullDereferenceBugTypePtr = &Checker->NullDereferenceBugType; } bool ento::shouldRegisterSmartPtrChecker(const CheckerManager &mgr) { 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 @@ -17,14 +17,18 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/Type.h" +#include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" +#include using namespace clang; using namespace ento; @@ -49,8 +53,6 @@ const LocationContext *LCtx, const CallEvent *Call) const; private: - ProgramStateRef updateTrackedRegion(const CallEvent &Call, CheckerContext &C, - const MemRegion *ThisValRegion) const; void handleReset(const CallEvent &Call, CheckerContext &C) const; void handleRelease(const CallEvent &Call, CheckerContext &C) const; void handleSwap(const CallEvent &Call, CheckerContext &C) const; @@ -131,11 +133,11 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call, CheckerContext &C) const { + ProgramStateRef State = C.getState(); if (!smartptr::isStdSmartPtrCall(Call)) return false; if (isNullAfterMoveMethod(Call)) { - ProgramStateRef State = C.getState(); const MemRegion *ThisR = cast(&Call)->getCXXThisVal().getAsRegion(); @@ -159,12 +161,46 @@ if (CC->getDecl()->isCopyOrMoveConstructor()) return false; - const MemRegion *ThisValRegion = CC->getCXXThisVal().getAsRegion(); - if (!ThisValRegion) + const MemRegion *ThisRegion = CC->getCXXThisVal().getAsRegion(); + if (!ThisRegion) return false; - auto State = updateTrackedRegion(Call, C, ThisValRegion); - C.addTransition(State); + if (Call.getNumArgs() == 0) { + auto NullVal = C.getSValBuilder().makeNull(); + State = State->set(ThisRegion, NullVal); + + C.addTransition( + State, C.getNoteTag([ThisRegion](PathSensitiveBugReport &BR, + llvm::raw_ostream &OS) { + if (&BR.getBugType() != smartptr::getNullDereferenceBugType() || + !BR.isInteresting(ThisRegion)) + return; + OS << "Default constructed smart pointer "; + ThisRegion->printPretty(OS); + OS << " is null"; + })); + } else { + const auto *TrackingExpr = Call.getArgExpr(0); + assert(TrackingExpr->getType()->isPointerType() && + "Adding a non pointer value to TrackedRegionMap"); + auto ArgVal = Call.getArgSVal(0); + State = State->set(ThisRegion, ArgVal); + + C.addTransition(State, C.getNoteTag([ThisRegion, TrackingExpr, + ArgVal](PathSensitiveBugReport &BR, + llvm::raw_ostream &OS) { + if (&BR.getBugType() != smartptr::getNullDereferenceBugType() || + !BR.isInteresting(ThisRegion)) + return; + bugreporter::trackExpressionValue(BR.getErrorNode(), TrackingExpr, BR); + OS << "Smart pointer "; + ThisRegion->printPretty(OS); + if (ArgVal.isZeroConstant()) + OS << " is constructed using a null value"; + else + OS << " is constructed"; + })); + } return true; } @@ -207,37 +243,65 @@ void SmartPtrModeling::handleReset(const CallEvent &Call, CheckerContext &C) const { + ProgramStateRef State = C.getState(); const auto *IC = dyn_cast(&Call); if (!IC) return; - const MemRegion *ThisValRegion = IC->getCXXThisVal().getAsRegion(); - if (!ThisValRegion) + const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion(); + if (!ThisRegion) return; - auto State = updateTrackedRegion(Call, C, ThisValRegion); - C.addTransition(State); + + assert(Call.getArgExpr(0)->getType()->isPointerType() && + "Adding a non pointer value to TrackedRegionMap"); + State = State->set(ThisRegion, Call.getArgSVal(0)); + const auto *TrackingExpr = Call.getArgExpr(0); + C.addTransition( + State, C.getNoteTag([ThisRegion, TrackingExpr](PathSensitiveBugReport &BR, + llvm::raw_ostream &OS) { + if (&BR.getBugType() != smartptr::getNullDereferenceBugType() || + !BR.isInteresting(ThisRegion)) + return; + bugreporter::trackExpressionValue(BR.getErrorNode(), TrackingExpr, BR); + OS << "Smart pointer "; + ThisRegion->printPretty(OS); + OS << " reset using a null value"; + })); // TODO: Make sure to ivalidate the region in the Store if we don't have // time to model all methods. } void SmartPtrModeling::handleRelease(const CallEvent &Call, CheckerContext &C) const { + ProgramStateRef State = C.getState(); const auto *IC = dyn_cast(&Call); if (!IC) return; - const MemRegion *ThisValRegion = IC->getCXXThisVal().getAsRegion(); - if (!ThisValRegion) + const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion(); + if (!ThisRegion) return; - auto State = updateTrackedRegion(Call, C, ThisValRegion); + const auto *InnerPointVal = State->get(ThisRegion); - const auto *InnerPointVal = State->get(ThisValRegion); if (InnerPointVal) { State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), *InnerPointVal); } - C.addTransition(State); + + auto ValueToUpdate = C.getSValBuilder().makeNull(); + State = State->set(ThisRegion, ValueToUpdate); + + C.addTransition(State, C.getNoteTag([ThisRegion](PathSensitiveBugReport &BR, + llvm::raw_ostream &OS) { + if (&BR.getBugType() != smartptr::getNullDereferenceBugType() || + !BR.isInteresting(ThisRegion)) + return; + + OS << "Smart pointer "; + ThisRegion->printPretty(OS); + OS << " is released and set to null"; + })); // TODO: Add support to enable MallocChecker to start tracking the raw // pointer. } @@ -267,27 +331,18 @@ State = updateSwappedRegion(State, ThisRegion, ArgRegionInnerPointerVal); State = updateSwappedRegion(State, ArgRegion, ThisRegionInnerPointerVal); - C.addTransition(State); -} - -ProgramStateRef -SmartPtrModeling::updateTrackedRegion(const CallEvent &Call, CheckerContext &C, - const MemRegion *ThisValRegion) const { - // TODO: Refactor and clean up handling too many things. - ProgramStateRef State = C.getState(); - auto NumArgs = Call.getNumArgs(); - - if (NumArgs == 0) { - auto NullSVal = C.getSValBuilder().makeNull(); - State = State->set(ThisValRegion, NullSVal); - } else if (NumArgs == 1) { - auto ArgVal = Call.getArgSVal(0); - assert(Call.getArgExpr(0)->getType()->isPointerType() && - "Adding a non pointer value to TrackedRegionMap"); - State = State->set(ThisValRegion, ArgVal); - } - - return State; + C.addTransition( + State, C.getNoteTag([ThisRegion, ArgRegion](PathSensitiveBugReport &BR, + llvm::raw_ostream &OS) { + if (&BR.getBugType() != smartptr::getNullDereferenceBugType() || + !BR.isInteresting(ThisRegion)) + return; + BR.markInteresting(ArgRegion); + OS << "Swapped null smart pointer "; + ArgRegion->printPretty(OS); + OS << " with smart pointer "; + ThisRegion->printPretty(OS); + })); } void ento::registerSmartPtrModeling(CheckerManager &Mgr) { diff --git a/clang/test/Analysis/smart-ptr-text-output.cpp b/clang/test/Analysis/smart-ptr-text-output.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/smart-ptr-text-output.cpp @@ -0,0 +1,119 @@ +// RUN: %clang_analyze_cc1\ +// RUN: -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr\ +// RUN: -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\ +// RUN: -analyzer-output=text -std=c++11 %s -verify=expected + +#include "Inputs/system-header-simulator-cxx.h" + +class A { +public: + A(){}; + void foo(); +}; + +A *return_null() { + return nullptr; +} + +void derefAfterDefaultCtr() { + std::unique_ptr P; // expected-note {{Default constructed 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 derefAfterCtrWithNull() { + A *NullInnerPtr = nullptr; // expected-note {{'NullInnerPtr' initialized to a null pointer value}} + std::unique_ptr P(NullInnerPtr); // expected-note {{Smart pointer 'P' is constructed using a null value}} + *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} + // expected-note@-1{{Dereference of null smart pointer 'P'}} +} + +void derefAfterCtrWithNullVariable() { + A *NullInnerPtr = nullptr; // expected-note {{'NullInnerPtr' initialized to a null pointer value}} + std::unique_ptr P(NullInnerPtr); // expected-note {{Smart pointer 'P' is constructed using a null value}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} + // expected-note@-1{{Dereference of null smart pointer 'P'}} +} + +void derefAfterRelease() { + std::unique_ptr P(new A()); + P.release(); // expected-note {{Smart pointer 'P' is released and set to null}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} + // expected-note@-1{{Dereference of null smart pointer 'P'}} +} + +void derefAfterReset() { + std::unique_ptr P(new A()); + P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} + // expected-note@-1{{Dereference of null smart pointer 'P'}} +} + +void derefAfterResetWithNull() { + A *NullInnerPtr = nullptr; // expected-note {{'NullInnerPtr' initialized to a null pointer value}} + std::unique_ptr P(new A()); + P.reset(NullInnerPtr); // expected-note {{Smart pointer 'P' reset using a null value}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} + // expected-note@-1{{Dereference of null smart pointer 'P'}} +} + +// FIXME: Fix this test when support is added for tracking raw pointer +// and mark the smart pointer as interesting based on that and add tags. +void derefOnReleasedNullRawPtr() { + std::unique_ptr P; // FIXME: add note "Default constructed smart pointer 'P' is null" + A *AP = P.release(); // expected-note {{'AP' initialized to a null pointer value}} + AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}} + // expected-note@-1{{Called C++ object pointer is null}} +} + +void derefOnSwappedNullPtr() { + std::unique_ptr P(new A()); + std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}} + P.swap(PNull); // expected-note {{Swapped null smart pointer 'PNull' with smart pointer 'P'}} + PNull->foo(); // No warning. + (*P).foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} + // expected-note@-1{{Dereference of null smart pointer 'P'}} +} + +// FIXME: Fix this test when "std::swap" is modeled seperately. +void derefOnStdSwappedNullPtr() { + std::unique_ptr P; + std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}} + std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:978 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}} + // expected-note@-1 {{Calling 'swap'}} + // expected-note@-2 {{Returning from 'swap'}} + PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}} + // expected-note@-1{{Dereference of null smart pointer 'PNull'}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} + // expected-note@-1{{Dereference of null smart pointer 'P'}} +} + +struct StructWithSmartPtr { // expected-note {{Default constructed smart pointer 'S.P' is null}} + std::unique_ptr P; +}; + +void derefAfterDefaultCtrInsideStruct() { + StructWithSmartPtr S; // expected-note {{Calling implicit default constructor for 'StructWithSmartPtr'}} + // expected-note@-1 {{Returning from default constructor for 'StructWithSmartPtr'}} + S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}} + // expected-note@-1{{Dereference of null smart pointer 'S.P'}} +} + +void noNoteTagsForNonInterestingRegion() { + std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}} + std::unique_ptr P1; // No note. + std::unique_ptr P2; // No note. + P1.release(); // No note. + P1.reset(); // No note. + P1.swap(P2); // No note. + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} + // expected-note@-1{{Dereference of null smart pointer 'P'}} +} + +void noNoteTagsForNonMatchingBugType() { + std::unique_ptr P; // No note. + std::unique_ptr P1; // No note. + P1 = std::move(P); // expected-note {{Smart pointer 'P' of type 'std::unique_ptr' is reset to null when moved from}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [cplusplus.Move]}} + // expected-note@-1 {{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}} +} diff --git a/clang/test/Analysis/smart-ptr.cpp b/clang/test/Analysis/smart-ptr.cpp --- a/clang/test/Analysis/smart-ptr.cpp +++ b/clang/test/Analysis/smart-ptr.cpp @@ -12,7 +12,7 @@ std::unique_ptr Q = std::move(P); if (Q) clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} - *Q.get() = 1; // no-warning + *Q.get() = 1; // no-warning if (P) clang_analyzer_warnIfReached(); // no-warning // TODO: Report a null dereference (instead). @@ -50,37 +50,38 @@ void derefAfterDefaultCtr() { std::unique_ptr P; - P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } void derefAfterCtrWithNull() { std::unique_ptr P(nullptr); - *P; // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } -void derefAfterCtrWithNullReturnMethod() { - std::unique_ptr P(return_null()); - P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} +void derefAfterCtrWithNullVariable() { + A *InnerPtr = nullptr; + std::unique_ptr P(InnerPtr); + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } void derefAfterRelease() { std::unique_ptr P(new A()); P.release(); clang_analyzer_numTimesReached(); // expected-warning {{1}} - P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } void derefAfterReset() { std::unique_ptr P(new A()); P.reset(); clang_analyzer_numTimesReached(); // expected-warning {{1}} - P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } void derefAfterResetWithNull() { std::unique_ptr P(new A()); P.reset(nullptr); - P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } void derefAfterResetWithNonNull() { @@ -102,6 +103,12 @@ AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}} } +void derefOnReleasedValidRawPtr() { + std::unique_ptr P(new A()); + A *AP = P.release(); + AP->foo(); // No warning. +} + void pass_smart_ptr_by_ref(std::unique_ptr &a); void pass_smart_ptr_by_const_ref(const std::unique_ptr &a); void pass_smart_ptr_by_rvalue_ref(std::unique_ptr &&a); @@ -118,7 +125,7 @@ { std::unique_ptr P; pass_smart_ptr_by_const_ref(P); - P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } { std::unique_ptr P; @@ -128,7 +135,7 @@ { std::unique_ptr P; pass_smart_ptr_by_const_rvalue_ref(std::move(P)); - P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } { std::unique_ptr P; @@ -138,7 +145,7 @@ { std::unique_ptr P; pass_smart_ptr_by_const_ptr(&P); - P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } } @@ -162,7 +169,7 @@ { StructWithSmartPtr S; pass_struct_with_smart_ptr_by_const_ref(S); - S.P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}} } { StructWithSmartPtr S; @@ -172,7 +179,7 @@ { StructWithSmartPtr S; pass_struct_with_smart_ptr_by_const_rvalue_ref(std::move(S)); - S.P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}} } { StructWithSmartPtr S; @@ -182,7 +189,7 @@ { StructWithSmartPtr S; pass_struct_with_smart_ptr_by_const_ptr(&S); - S.P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}} } } @@ -207,24 +214,24 @@ std::unique_ptr PNull; P.swap(PNull); PNull->foo(); // No warning. - (*P).foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + (*P).foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } void derefOnStdSwappedNullPtr() { std::unique_ptr P; std::unique_ptr PNull; std::swap(P, PNull); - PNull->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} - P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}} + P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } void derefOnSwappedValidPtr() { std::unique_ptr P(new A()); std::unique_ptr PValid(new A()); P.swap(PValid); - (*P).foo(); // No warning. + (*P).foo(); // No warning. PValid->foo(); // No warning. std::swap(P, PValid); - P->foo(); // No warning. + P->foo(); // No warning. PValid->foo(); // No warning. }