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 @@ -56,13 +56,15 @@ void handleReset(const CallEvent &Call, CheckerContext &C) const; void handleRelease(const CallEvent &Call, CheckerContext &C) const; void handleSwap(const CallEvent &Call, CheckerContext &C) const; + void handleGet(const CallEvent &Call, CheckerContext &C) const; using SmartPtrMethodHandlerFn = void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const; CallDescriptionMap SmartPtrMethodHandlers{ {{"reset"}, &SmartPtrModeling::handleReset}, {{"release"}, &SmartPtrModeling::handleRelease}, - {{"swap", 1}, &SmartPtrModeling::handleSwap}}; + {{"swap", 1}, &SmartPtrModeling::handleSwap}, + {{"get"}, &SmartPtrModeling::handleGet}}; }; } // end of anonymous namespace @@ -345,6 +347,27 @@ })); } +void SmartPtrModeling::handleGet(const CallEvent &Call, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); + const auto *IC = dyn_cast(&Call); + if (!IC) + return; + + const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion(); + if (!ThisRegion) + return; + + const auto *InnerPointVal = State->get(ThisRegion); + if (!InnerPointVal) + return; + + State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), + *InnerPointVal); + //TODO: Add NoteTag, for how the raw pointer got using 'get' method. + C.addTransition(State); +} + void ento::registerSmartPtrModeling(CheckerManager &Mgr) { auto *Checker = Mgr.registerChecker(); Checker->ModelSmartPtrDereference = 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 @@ -117,3 +117,18 @@ 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'}} } + +void derefOnRawPtrFromGetOnNullPtr() { + std::unique_ptr P; // FIXME: add note "Default constructed smart pointer 'P' is null" + P.get()->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}} + // expected-note@-1 {{Called C++ object pointer is null}} +} + +void derefOnRawPtrFromGetOnValidPtr() { + std::unique_ptr P(new A()); + P.get()->foo(); // No warning. +} + +void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr P) { + P.get()->foo(); // No warning. +} 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 @@ -235,3 +235,17 @@ P->foo(); // No warning. PValid->foo(); // No warning. } + +void derefOnRawPtrFromGetOnNullPtr() { + std::unique_ptr P; + P.get()->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}} +} + +void derefOnRawPtrFromGetOnValidPtr() { + std::unique_ptr P(new A()); + P.get()->foo(); // No warning. +} + +void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr P) { + P.get()->foo(); // No warning. +}