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<void(PathSensitiveBugReport &BR, llvm::raw_ostream &OS)> &&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);
/// 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
#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<check::PreCall> {
- BugType NullDereferenceBugType{this, "Null SmartPtr dereference",
- "C++ Smart Pointer"};
+static const BugType *NullDereferenceBugTypePtr;
+
+class SmartPtrChecker : public Checker<check::PreCall> {
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))
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<PathSensitiveBugReport>(
- 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<PathSensitiveBugReport>(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>();
+ SmartPtrChecker *Checker = Mgr.registerChecker<SmartPtrChecker>();
+ NullDereferenceBugTypePtr = &Checker->NullDereferenceBugType;
}
bool ento::shouldRegisterSmartPtrChecker(const CheckerManager &mgr) {
#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 <string>
using namespace clang;
using namespace ento;
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;
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<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();
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<TrackedRegionMap>(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<TrackedRegionMap>(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;
}
void SmartPtrModeling::handleReset(const CallEvent &Call,
CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
const auto *IC = dyn_cast<CXXInstanceCall>(&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<TrackedRegionMap>(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<CXXInstanceCall>(&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<TrackedRegionMap>(ThisRegion);
- const auto *InnerPointVal = State->get<TrackedRegionMap>(ThisValRegion);
if (InnerPointVal) {
State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
*InnerPointVal);
}
- C.addTransition(State);
+
+ auto ValueToUpdate = C.getSValBuilder().makeNull();
+ State = State->set<TrackedRegionMap>(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.
}
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<TrackedRegionMap>(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<TrackedRegionMap>(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) {
--- /dev/null
+// 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<A> 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<A> 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<A> 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<A> 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<A> 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<A> 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<A> 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<A> P(new A());
+ std::unique_ptr<A> 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<A> P;
+ std::unique_ptr<A> 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<A>'}}
+ // expected-note@-2 {{Returning from 'swap<A>'}}
+ 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<A> 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<A> P; // expected-note {{Default constructed smart pointer 'P' is null}}
+ std::unique_ptr<A> P1; // No note.
+ std::unique_ptr<A> 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<A> P; // No note.
+ std::unique_ptr<A> 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'}}
+}
std::unique_ptr<int> 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).
void derefAfterDefaultCtr() {
std::unique_ptr<A> 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<A> 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<A> P(return_null());
- P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+void derefAfterCtrWithNullVariable() {
+ A *InnerPtr = nullptr;
+ std::unique_ptr<A> P(InnerPtr);
+ P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
}
void derefAfterRelease() {
std::unique_ptr<A> 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<A> 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<A> 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() {
AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
}
+void derefOnReleasedValidRawPtr() {
+ std::unique_ptr<A> P(new A());
+ A *AP = P.release();
+ AP->foo(); // No warning.
+}
+
void pass_smart_ptr_by_ref(std::unique_ptr<A> &a);
void pass_smart_ptr_by_const_ref(const std::unique_ptr<A> &a);
void pass_smart_ptr_by_rvalue_ref(std::unique_ptr<A> &&a);
{
std::unique_ptr<A> 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<A> P;
{
std::unique_ptr<A> 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<A> P;
{
std::unique_ptr<A> 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]}}
}
}
{
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;
{
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;
{
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]}}
}
}
std::unique_ptr<A> 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<A> P;
std::unique_ptr<A> 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<A> P(new A());
std::unique_ptr<A> 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.
}