RedDocMD updated this revision to Diff 350067.
RedDocMD added a comment.

Accounting for std::make_unique_for_overwrite


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103750/new/

https://reviews.llvm.org/D103750

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp

Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -35,11 +35,19 @@
 using namespace ento;
 
 namespace {
+
+enum class MakeUniqueKind {
+  Regular, // ie, std::make_unique
+  ForOverwrite, // ie, std::make_unique_for_overwrite
+  None // ie, is neither of the above two
+};
+
 class SmartPtrModeling
     : public Checker<eval::Call, check::DeadSymbols, check::RegionChanges,
                      check::LiveSymbols> {
 
   bool isBoolConversionMethod(const CallEvent &Call) const;
+  MakeUniqueKind isStdMakeUniqueCall(const CallEvent &Call) const;
 
 public:
   // Whether the checker should model for null dereferences of smart pointers.
@@ -68,6 +76,7 @@
   bool updateMovedSmartPointers(CheckerContext &C, const MemRegion *ThisRegion,
                                 const MemRegion *OtherSmartPtrRegion) const;
   void handleBoolConversion(const CallEvent &Call, CheckerContext &C) const;
+  void handleMakeUnique(const CallEvent &Call, CheckerContext &C, MakeUniqueKind Kind) const;
 
   using SmartPtrMethodHandlerFn =
       void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const;
@@ -175,8 +184,34 @@
   return CD && CD->getConversionType()->isBooleanType();
 }
 
+MakeUniqueKind SmartPtrModeling::isStdMakeUniqueCall(const CallEvent &Call) const {
+  if (Call.getKind() != CallEventKind::CE_Function)
+    return MakeUniqueKind::None;
+  const auto *D = Call.getDecl();
+  if (!D)
+    return MakeUniqueKind::None;
+  const auto *FTD = llvm::dyn_cast<FunctionDecl>(D);
+  if (!FTD)
+    return MakeUniqueKind::None;
+  if (FTD->getDeclName().isIdentifier()) {
+    StringRef Name = FTD->getName();
+    if (Name == "make_unique")
+      return MakeUniqueKind::Regular;
+    else if (Name == "make_unique_for_overwrite")
+      return MakeUniqueKind::ForOverwrite;
+  }
+  return MakeUniqueKind::None;
+}
+
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
                                 CheckerContext &C) const {
+
+  MakeUniqueKind Kind = isStdMakeUniqueCall(Call);
+  if (Kind != MakeUniqueKind::None) {
+    handleMakeUnique(Call, C, Kind);
+    return true;
+  }
+
   ProgramStateRef State = C.getState();
   if (!smartptr::isStdSmartPtrCall(Call))
     return false;
@@ -214,7 +249,6 @@
   if (const auto *CC = dyn_cast<CXXConstructorCall>(&Call)) {
     if (CC->getDecl()->isCopyConstructor())
       return false;
-
     const MemRegion *ThisRegion = CC->getCXXThisVal().getAsRegion();
     if (!ThisRegion)
       return false;
@@ -272,6 +306,33 @@
   return C.isDifferent();
 }
 
+void SmartPtrModeling::handleMakeUnique(const CallEvent &Call,
+                                        CheckerContext &C, MakeUniqueKind Kind) const {
+  assert(Kind != MakeUniqueKind::None && "Call is not to make_unique or make_unique_for_overwrite");
+
+  const auto *OriginExpr = Call.getOriginExpr();
+  const auto *LocCtx = C.getLocationContext();
+
+  ProgramStateRef State = C.getState();
+
+  if (Kind == MakeUniqueKind::Regular) {
+      // With make unique it is not possible to make a null smart pointer.
+      // So we can set the SVal for Call.getOriginExpr() to be non-null
+      auto ExprVal = C.getSValBuilder().conjureSymbolVal(
+          OriginExpr, LocCtx, Call.getResultType(), C.blockCount());
+      State = State->assume(ExprVal, true);
+      State = State->BindExpr(OriginExpr, LocCtx, ExprVal);
+  } else {
+      // Technically, we are creating an uninitialized unique_ptr.
+      // So the value inside is *not* null, but we might as well set it
+      // so that the user gets better warnings.
+      auto ExprVal = C.getSValBuilder().makeZeroVal(Call.getResultType());
+      State = State->BindExpr(OriginExpr, LocCtx, ExprVal);
+  }
+
+  C.addTransition(State);
+}
+
 void SmartPtrModeling::checkDeadSymbols(SymbolReaper &SymReaper,
                                         CheckerContext &C) const {
   ProgramStateRef State = C.getState();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to