[clang] 20e271a - [analyzer] Warning for default constructed unique_ptr dereference
Nithin Vadukkumchery Rajendrakumar via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 8 00:52:05 PDT 2020
Author: Nithin Vadukkumchery Rajendrakumar
Date: 2020-07-08T09:51:02+02:00
New Revision: 20e271a98de5609e22766e56f9c374b150f06982
URL: https://github.com/llvm/llvm-project/commit/20e271a98de5609e22766e56f9c374b150f06982
DIFF: https://github.com/llvm/llvm-project/commit/20e271a98de5609e22766e56f9c374b150f06982.diff
LOG: [analyzer] Warning for default constructed unique_ptr dereference
Summary: Add support for warning incase of default constructed unique pointer dereferences
Reviewed By: NoQ, Szelethus, vsavchenko, xazax.hun
Tags: #clang
Differential Revision: https://reviews.llvm.org/D81315
Added:
clang/lib/StaticAnalyzer/Checkers/SmartPtr.h
clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp
Modified:
clang/docs/analyzer/checkers.rst
clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
clang/test/Analysis/Inputs/system-header-simulator-cxx.h
clang/test/Analysis/analyzer-config.c
clang/test/Analysis/smart-ptr.cpp
clang/test/Analysis/use-after-move.cpp
Removed:
################################################################################
diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index d14bd2d68af9..1583da7aff09 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -1836,6 +1836,19 @@ Check unreachable code.
[x retain]; // warn
}
+.. _alpha-cplusplus-SmartPtr:
+
+alpha.cplusplus.SmartPtr (C++)
+""""""""""""""""""""""""""""""
+Check for dereference of null smart pointers.
+
+.. code-block:: cpp
+
+ void deref_smart_ptr() {
+ std::unique_ptr<int> P;
+ *P; // warn: dereference of a default constructed smart unique_ptr
+ }
+
alpha.llvm
^^^^^^^^^^
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index dc1269890f93..cbd925400328 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -577,9 +577,17 @@ def CXXSelfAssignmentChecker : Checker<"SelfAssignment">,
Documentation<NotDocumented>,
Hidden;
-def SmartPtrModeling: Checker<"SmartPtr">,
+def SmartPtrModeling: Checker<"SmartPtrModeling">,
HelpText<"Model behavior of C++ smart pointers">,
Documentation<NotDocumented>,
+ CheckerOptions<[
+ CmdLineOption<Boolean,
+ "ModelSmartPtrDereference",
+ "Enable modeling for SmartPtr null dereferences",
+ "false",
+ InAlpha,
+ Hide>,
+ ]>,
Hidden;
def MoveChecker: Checker<"Move">,
@@ -736,6 +744,11 @@ def MismatchedIteratorChecker : Checker<"MismatchedIterator">,
Dependencies<[IteratorModeling]>,
Documentation<HasAlphaDocumentation>;
+def SmartPtrChecker: Checker<"SmartPtr">,
+ HelpText<"Find the dereference of null SmrtPtr">,
+ Dependencies<[SmartPtrModeling]>,
+ Documentation<HasAlphaDocumentation>;
+
} // end: "alpha.cplusplus"
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index a71469e90ea2..d75f9f63286d 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -788,6 +788,10 @@ class CXXMemberOperatorCall : public CXXInstanceCall {
// to implicit this-parameter on the declaration.
return CallArgumentIndex + 1;
}
+
+ OverloadedOperatorKind getOverloadedOperator() const {
+ return getOriginExpr()->getOperator();
+ }
};
/// Represents an implicit call to a C++ destructor.
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 80cac237fc3b..9be1fdeb3ebf 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -98,6 +98,7 @@ add_clang_library(clangStaticAnalyzerCheckers
ReturnValueChecker.cpp
RunLoopAutoreleaseLeakChecker.cpp
SimpleStreamChecker.cpp
+ SmartPtrChecker.cpp
SmartPtrModeling.cpp
StackAddrEscapeChecker.cpp
StdLibraryFunctionsChecker.cpp
diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtr.h b/clang/lib/StaticAnalyzer/Checkers/SmartPtr.h
new file mode 100644
index 000000000000..89b8965e4c9a
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtr.h
@@ -0,0 +1,40 @@
+//=== SmartPtr.h - Tracking smart pointer state. -------------------*- C++ -*-//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines inter-checker API for the smart pointer modeling. It allows
+// dependent checkers to figure out if an smart pointer is null or not.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_SMARTPTR_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_SMARTPTR_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+
+namespace clang {
+namespace ento {
+namespace smartptr {
+
+/// Set of STL smart pointer class which we are trying to model.
+const llvm::StringSet<> StdSmartPtrs = {
+ "shared_ptr",
+ "unique_ptr",
+ "weak_ptr",
+};
+
+/// Returns true if the event call is on smart pointer.
+bool isStdSmartPtrCall(const CallEvent &Call);
+
+/// Returns whether the smart pointer is null or not.
+bool isNullSmartPtr(const ProgramStateRef State, const MemRegion *ThisRegion);
+
+} // namespace smartptr
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_SMARTPTR_H
diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp
new file mode 100644
index 000000000000..7bb25f397d01
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp
@@ -0,0 +1,80 @@
+// SmartPtrChecker.cpp - Check for smart pointer dereference - C++ --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a checker that check for null dereference of C++ smart
+// pointer.
+//
+//===----------------------------------------------------------------------===//
+#include "SmartPtr.h"
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/Type.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/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class SmartPtrChecker : public Checker<check::PreCall> {
+ BugType NullDereferenceBugType{this, "Null SmartPtr dereference",
+ "C++ Smart Pointer"};
+
+public:
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+
+private:
+ void reportBug(CheckerContext &C, const CallEvent &Call) const;
+};
+} // end of anonymous namespace
+
+void SmartPtrChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ if (!smartptr::isStdSmartPtrCall(Call))
+ return;
+ ProgramStateRef State = C.getState();
+ const auto *OC = dyn_cast<CXXMemberOperatorCall>(&Call);
+ if (!OC)
+ return;
+ const MemRegion *ThisRegion = OC->getCXXThisVal().getAsRegion();
+ if (!ThisRegion)
+ return;
+
+ OverloadedOperatorKind OOK = OC->getOverloadedOperator();
+ if (OOK == OO_Star || OOK == OO_Arrow) {
+ if (smartptr::isNullSmartPtr(State, ThisRegion))
+ reportBug(C, Call);
+ }
+}
+
+void SmartPtrChecker::reportBug(CheckerContext &C,
+ const CallEvent &Call) const {
+ ExplodedNode *ErrNode = C.generateErrorNode();
+ if (!ErrNode)
+ return;
+
+ auto R = std::make_unique<PathSensitiveBugReport>(
+ NullDereferenceBugType, "Dereference of null smart pointer", ErrNode);
+ C.emitReport(std::move(R));
+}
+
+void ento::registerSmartPtrChecker(CheckerManager &Mgr) {
+ Mgr.registerChecker<SmartPtrChecker>();
+}
+
+bool ento::shouldRegisterSmartPtrChecker(const CheckerManager &mgr) {
+ const LangOptions &LO = mgr.getLangOpts();
+ return LO.CPlusPlus;
+}
diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
index 8250fd46b926..91f289078814 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -12,27 +12,80 @@
//===----------------------------------------------------------------------===//
#include "Move.h"
+#include "SmartPtr.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/Type.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/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
using namespace clang;
using namespace ento;
namespace {
-class SmartPtrModeling : public Checker<eval::Call> {
+class SmartPtrModeling : public Checker<eval::Call, check::DeadSymbols> {
+
bool isNullAfterMoveMethod(const CallEvent &Call) const;
public:
+ // Whether the checker should model for null dereferences of smart pointers.
+ DefaultBool ModelSmartPtrDereference;
bool evalCall(const CallEvent &Call, CheckerContext &C) const;
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+ void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) 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;
+
+ using SmartPtrMethodHandlerFn =
+ void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const;
+ CallDescriptionMap<SmartPtrMethodHandlerFn> SmartPtrMethodHandlers{
+ {{"reset"}, &SmartPtrModeling::handleReset},
+ {{"release"}, &SmartPtrModeling::handleRelease},
+ {{"swap", 1}, &SmartPtrModeling::handleSwap}};
};
} // end of anonymous namespace
+REGISTER_MAP_WITH_PROGRAMSTATE(TrackedRegionMap, const MemRegion *, SVal)
+
+// Define the inter-checker API.
+namespace clang {
+namespace ento {
+namespace smartptr {
+bool isStdSmartPtrCall(const CallEvent &Call) {
+ const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(Call.getDecl());
+ if (!MethodDecl || !MethodDecl->getParent())
+ return false;
+
+ const auto *RecordDecl = MethodDecl->getParent();
+ if (!RecordDecl || !RecordDecl->getDeclContext()->isStdNamespace())
+ return false;
+
+ if (RecordDecl->getDeclName().isIdentifier()) {
+ return smartptr::StdSmartPtrs.count(RecordDecl->getName().lower());
+ }
+ return false;
+}
+
+bool isNullSmartPtr(const ProgramStateRef State, const MemRegion *ThisRegion) {
+ const auto *InnerPointVal = State->get<TrackedRegionMap>(ThisRegion);
+ return InnerPointVal && InnerPointVal->isZeroConstant();
+}
+} // namespace smartptr
+} // namespace ento
+} // namespace clang
+
bool SmartPtrModeling::isNullAfterMoveMethod(const CallEvent &Call) const {
// TODO: Update CallDescription to support anonymous calls?
// TODO: Handle other methods, such as .get() or .release().
@@ -44,27 +97,133 @@ bool SmartPtrModeling::isNullAfterMoveMethod(const CallEvent &Call) const {
bool SmartPtrModeling::evalCall(const CallEvent &Call,
CheckerContext &C) const {
- if (!isNullAfterMoveMethod(Call))
+
+ if (!smartptr::isStdSmartPtrCall(Call))
return false;
- ProgramStateRef State = C.getState();
- const MemRegion *ThisR =
- cast<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();
+ if (isNullAfterMoveMethod(Call)) {
+ ProgramStateRef State = C.getState();
+ const MemRegion *ThisR =
+ cast<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();
+
+ if (!move::isMovedFrom(State, ThisR)) {
+ // TODO: Model this case as well. At least, avoid invalidation of globals.
+ return false;
+ }
+
+ // TODO: Add a note to bug reports describing this decision.
+ C.addTransition(
+ State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
+ C.getSValBuilder().makeZeroVal(Call.getResultType())));
+ return true;
+ }
- if (!move::isMovedFrom(State, ThisR)) {
- // TODO: Model this case as well. At least, avoid invalidation of globals.
+ if (!ModelSmartPtrDereference)
return false;
+
+ if (const auto *CC = dyn_cast<CXXConstructorCall>(&Call)) {
+ if (CC->getDecl()->isCopyOrMoveConstructor())
+ return false;
+
+ const MemRegion *ThisValRegion = CC->getCXXThisVal().getAsRegion();
+ if (!ThisValRegion)
+ return false;
+
+ auto State = updateTrackedRegion(Call, C, ThisValRegion);
+ C.addTransition(State);
+ return true;
+ }
+
+ const SmartPtrMethodHandlerFn *Handler = SmartPtrMethodHandlers.lookup(Call);
+ if (!Handler)
+ return false;
+ (this->**Handler)(Call, C);
+
+ return C.isDifferent();
+}
+
+void SmartPtrModeling::checkDeadSymbols(SymbolReaper &SymReaper,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ // Clean up dead regions from the region map.
+ TrackedRegionMapTy TrackedRegions = State->get<TrackedRegionMap>();
+ for (auto E : TrackedRegions) {
+ const MemRegion *Region = E.first;
+ bool IsRegDead = !SymReaper.isLiveRegion(Region);
+
+ if (IsRegDead)
+ State = State->remove<TrackedRegionMap>(Region);
+ }
+ C.addTransition(State);
+}
+
+void SmartPtrModeling::handleReset(const CallEvent &Call,
+ CheckerContext &C) const {
+ const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
+ if (!IC)
+ return;
+
+ const MemRegion *ThisValRegion = IC->getCXXThisVal().getAsRegion();
+ if (!ThisValRegion)
+ return;
+ auto State = updateTrackedRegion(Call, C, ThisValRegion);
+ C.addTransition(State);
+ // TODO: Make sure to ivalidate the the region in the Store if we don't have
+ // time to model all methods.
+}
+
+void SmartPtrModeling::handleRelease(const CallEvent &Call,
+ CheckerContext &C) const {
+ const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
+ if (!IC)
+ return;
+
+ const MemRegion *ThisValRegion = IC->getCXXThisVal().getAsRegion();
+ if (!ThisValRegion)
+ return;
+
+ auto State = updateTrackedRegion(Call, C, ThisValRegion);
+
+ const auto *InnerPointVal = State->get<TrackedRegionMap>(ThisValRegion);
+ if (InnerPointVal) {
+ State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
+ *InnerPointVal);
+ }
+ C.addTransition(State);
+ // TODO: Add support to enable MallocChecker to start tracking the raw
+ // pointer.
+}
+
+void SmartPtrModeling::handleSwap(const CallEvent &Call,
+ CheckerContext &C) const {
+ // TODO: Add support to handle swap method.
+}
+
+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);
}
- // TODO: Add a note to bug reports describing this decision.
- C.addTransition(
- State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
- C.getSValBuilder().makeZeroVal(Call.getResultType())));
- return true;
+ return State;
}
void ento::registerSmartPtrModeling(CheckerManager &Mgr) {
- Mgr.registerChecker<SmartPtrModeling>();
+ auto *Checker = Mgr.registerChecker<SmartPtrModeling>();
+ Checker->ModelSmartPtrDereference =
+ Mgr.getAnalyzerOptions().getCheckerBooleanOption(
+ Checker, "ModelSmartPtrDereference");
}
bool ento::shouldRegisterSmartPtrModeling(const CheckerManager &mgr) {
diff --git a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h
index 4729b0439ad0..fe4b9d081e9c 100644
--- a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -946,10 +946,15 @@ namespace std {
template <typename T> // TODO: Implement the stub for deleter.
class unique_ptr {
public:
+ unique_ptr() {}
+ unique_ptr(T *) {}
unique_ptr(const unique_ptr &) = delete;
unique_ptr(unique_ptr &&);
T *get() const;
+ T *release() const;
+ void reset(T *p = nullptr) const;
+ void swap(unique_ptr<T> &p) const;
typename std::add_lvalue_reference<T>::type operator*() const;
T *operator->() const;
diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c
index 56c749cc45d8..7599cb052d44 100644
--- a/clang/test/Analysis/analyzer-config.c
+++ b/clang/test/Analysis/analyzer-config.c
@@ -40,6 +40,7 @@
// CHECK-NEXT: core.CallAndMessage:ParameterCount = true
// CHECK-NEXT: core.CallAndMessage:UndefReceiver = true
// CHECK-NEXT: cplusplus.Move:WarnOn = KnownsAndLocals
+// CHECK-NEXT: cplusplus.SmartPtrModeling:ModelSmartPtrDereference = false
// CHECK-NEXT: crosscheck-with-z3 = false
// CHECK-NEXT: ctu-dir = ""
// CHECK-NEXT: ctu-import-threshold = 8
diff --git a/clang/test/Analysis/smart-ptr.cpp b/clang/test/Analysis/smart-ptr.cpp
index ae6966b4e6f4..4ab7e2bbd3bf 100644
--- a/clang/test/Analysis/smart-ptr.cpp
+++ b/clang/test/Analysis/smart-ptr.cpp
@@ -1,16 +1,18 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection\
-// RUN: -analyzer-checker cplusplus.Move,cplusplus.SmartPtr\
+// RUN: -analyzer-checker cplusplus.Move,alpha.cplusplus.SmartPtr\
+// RUN: -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
// RUN: -std=c++11 -verify %s
#include "Inputs/system-header-simulator-cxx.h"
void clang_analyzer_warnIfReached();
+void clang_analyzer_numTimesReached();
void derefAfterMove(std::unique_ptr<int> P) {
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).
@@ -26,3 +28,76 @@ void bar(S *s, void (S::*func)(void)) {
(s->*func)(); // no-crash
}
} // namespace testUnknownCallee
+
+class A {
+public:
+ A(){};
+ void foo();
+};
+
+A *return_null() {
+ return nullptr;
+}
+
+void derefAfterValidCtr() {
+ std::unique_ptr<A> P(new A());
+ P->foo(); // No warning.
+}
+
+void derefOfUnknown(std::unique_ptr<A> P) {
+ P->foo(); // No warning.
+}
+
+void derefAfterDefaultCtr() {
+ std::unique_ptr<A> P;
+ P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefAfterCtrWithNull() {
+ std::unique_ptr<A> P(nullptr);
+ *P; // expected-warning {{Dereference of null smart pointer [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 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]}}
+}
+
+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]}}
+}
+
+void derefAfterResetWithNull() {
+ std::unique_ptr<A> P(new A());
+ P.reset(nullptr);
+ P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefAfterResetWithNonNull() {
+ std::unique_ptr<A> P;
+ P.reset(new A());
+ P->foo(); // No warning.
+}
+
+void derefAfterReleaseAndResetWithNonNull() {
+ std::unique_ptr<A> P(new A());
+ P.release();
+ P.reset(new A());
+ P->foo(); // No warning.
+}
+
+void derefOnReleasedNullRawPtr() {
+ std::unique_ptr<A> P;
+ A *AP = P.release();
+ AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
+}
diff --git a/clang/test/Analysis/use-after-move.cpp b/clang/test/Analysis/use-after-move.cpp
index c25f4393cdf9..d7b6c74fabd6 100644
--- a/clang/test/Analysis/use-after-move.cpp
+++ b/clang/test/Analysis/use-after-move.cpp
@@ -1,36 +1,36 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
// RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
// RUN: -analyzer-config exploration_strategy=unexplored_first_queue\
-// RUN: -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN: -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
// RUN: -verify=expected,peaceful,non-aggressive
// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
// RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
// RUN: -analyzer-config exploration_strategy=dfs -DDFS\
-// RUN: -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN: -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
// RUN: -verify=expected,peaceful,non-aggressive
// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
// RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
// RUN: -analyzer-config exploration_strategy=unexplored_first_queue\
// RUN: -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
-// RUN: -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN: -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
// RUN: -verify=expected,non-aggressive
// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move -verify %s\
// RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
// RUN: -analyzer-config exploration_strategy=dfs -DDFS\
// RUN: -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
-// RUN: -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN: -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
// RUN: -verify=expected,non-aggressive
// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
// RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
// RUN: -analyzer-config exploration_strategy=unexplored_first_queue\
// RUN: -analyzer-config cplusplus.Move:WarnOn=All\
-// RUN: -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN: -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
// RUN: -verify=expected,peaceful,aggressive
// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
// RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
// RUN: -analyzer-config exploration_strategy=dfs -DDFS\
// RUN: -analyzer-config cplusplus.Move:WarnOn=All\
-// RUN: -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN: -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
// RUN: -verify=expected,peaceful,aggressive
// RUN: not %clang_analyze_cc1 -verify %s \
@@ -49,7 +49,7 @@
// RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
// RUN: -analyzer-config exploration_strategy=dfs -DDFS\
// RUN: -analyzer-config cplusplus.Move:WarnOn=All -DAGGRESSIVE_DFS\
-// RUN: -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN: -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
// RUN: -verify=expected,peaceful,aggressive %s 2>&1 | FileCheck %s
#include "Inputs/system-header-simulator-cxx.h"
More information about the cfe-commits
mailing list