llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Vidur (vidur2)

<details>
<summary>Changes</summary>

Hi, I am working on a PR for issue #<!-- -->153300. Currently I dont have a 
regression test or anything for this yet. This is just the initial fix.

---

Patch is 29.71 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/155131.diff


2 Files Affected:

- (modified) clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (+160-135) 
- (modified) clang/test/Analysis/NewDeleteLeaks.cpp (+140) 


``````````diff
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index efb980962e811..eda1c73b6e029 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -231,12 +231,15 @@ class RefState {
 
   LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
     switch (K) {
-#define CASE(ID) case ID: OS << #ID; break;
-    CASE(Allocated)
-    CASE(AllocatedOfSizeZero)
-    CASE(Released)
-    CASE(Relinquished)
-    CASE(Escaped)
+#define CASE(ID)                                                               
\
+  case ID:                                                                     
\
+    OS << #ID;                                                                 
\
+    break;
+      CASE(Allocated)
+      CASE(AllocatedOfSizeZero)
+      CASE(Released)
+      CASE(Relinquished)
+      CASE(Escaped)
     }
   }
 
@@ -304,8 +307,7 @@ struct ReallocPair {
     ID.AddPointer(ReallocatedSym);
   }
   bool operator==(const ReallocPair &X) const {
-    return ReallocatedSym == X.ReallocatedSym &&
-           Kind == X.Kind;
+    return ReallocatedSym == X.ReallocatedSym && Kind == X.Kind;
   }
 };
 
@@ -422,27 +424,28 @@ class MallocChecker
   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
   void checkNewAllocator(const CXXAllocatorCall &Call, CheckerContext &C) 
const;
-  void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) 
const;
+  void checkPostObjCMessage(const ObjCMethodCall &Call,
+                            CheckerContext &C) const;
   void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
   void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
   void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const;
   ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
-                            bool Assumption) const;
+                             bool Assumption) const;
   void checkLocation(SVal l, bool isLoad, const Stmt *S,
                      CheckerContext &C) const;
 
   ProgramStateRef checkPointerEscape(ProgramStateRef State,
-                                    const InvalidatedSymbols &Escaped,
-                                    const CallEvent *Call,
-                                    PointerEscapeKind Kind) const;
+                                     const InvalidatedSymbols &Escaped,
+                                     const CallEvent *Call,
+                                     PointerEscapeKind Kind) const;
   ProgramStateRef checkConstPointerEscape(ProgramStateRef State,
                                           const InvalidatedSymbols &Escaped,
                                           const CallEvent *Call,
                                           PointerEscapeKind Kind) const;
 
-  void printState(raw_ostream &Out, ProgramStateRef State,
-                  const char *NL, const char *Sep) const override;
+  void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
+                  const char *Sep) const override;
 
   StringRef getDebugTag() const override { return "MallocChecker"; }
 
@@ -789,9 +792,10 @@ class MallocChecker
   ///
   /// We assume that pointers do not escape through calls to system functions
   /// not handled by this checker.
-  bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(const CallEvent *Call,
-                                   ProgramStateRef State,
-                                   SymbolRef &EscapingSymbol) const;
+  bool
+  mayFreeAnyEscapedMemoryOrIsModeledExplicitly(const CallEvent *Call,
+                                               ProgramStateRef State,
+                                               SymbolRef &EscapingSymbol) 
const;
 
   /// Implementation of the checkPointerEscape callbacks.
   [[nodiscard]] ProgramStateRef
@@ -1253,9 +1257,8 @@ MallocChecker::performKernelMalloc(const CallEvent &Call, 
CheckerContext &C,
   NonLoc ZeroFlag = C.getSValBuilder()
                         .makeIntVal(*KernelZeroFlagVal, FlagsEx->getType())
                         .castAs<NonLoc>();
-  SVal MaskedFlagsUC = C.getSValBuilder().evalBinOpNN(State, BO_And,
-                                                      Flags, ZeroFlag,
-                                                      FlagsEx->getType());
+  SVal MaskedFlagsUC = C.getSValBuilder().evalBinOpNN(
+      State, BO_And, Flags, ZeroFlag, FlagsEx->getType());
   if (MaskedFlagsUC.isUnknownOrUndef())
     return std::nullopt;
   DefinedSVal MaskedFlags = MaskedFlagsUC.castAs<DefinedSVal>();
@@ -1485,7 +1488,8 @@ void MallocChecker::checkGMemdup(ProgramStateRef State, 
const CallEvent &Call,
 void MallocChecker::checkGMallocN(ProgramStateRef State, const CallEvent &Call,
                                   CheckerContext &C) const {
   SVal Init = UndefinedVal();
-  SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), 
Call.getArgExpr(1));
+  SVal TotalSize =
+      evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
   State = MallocMemAux(C, Call, TotalSize, Init, State,
                        AllocationFamily(AF_Malloc));
   State = ProcessZeroAllocCheck(C, Call, 0, State);
@@ -1497,7 +1501,8 @@ void MallocChecker::checkGMallocN0(ProgramStateRef State, 
const CallEvent &Call,
                                    CheckerContext &C) const {
   SValBuilder &SB = C.getSValBuilder();
   SVal Init = SB.makeZeroVal(SB.getContext().CharTy);
-  SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), 
Call.getArgExpr(1));
+  SVal TotalSize =
+      evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
   State = MallocMemAux(C, Call, TotalSize, Init, State,
                        AllocationFamily(AF_Malloc));
   State = ProcessZeroAllocCheck(C, Call, 0, State);
@@ -2061,8 +2066,8 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext 
&C,
 
 /// Checks if the previous call to free on the given symbol failed - if free
 /// failed, returns true. Also, returns the corresponding return value symbol.
-static bool didPreviousFreeFail(ProgramStateRef State,
-                                SymbolRef Sym, SymbolRef &RetStatusSymbol) {
+static bool didPreviousFreeFail(ProgramStateRef State, SymbolRef Sym,
+                                SymbolRef &RetStatusSymbol) {
   const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
   if (Ret) {
     assert(*Ret && "We should not store the null return symbol");
@@ -2318,8 +2323,7 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr 
*ArgExpr,
       // Check if the memory location being freed is the actual location
       // allocated, or an offset.
       RegionOffset Offset = R->getAsOffset();
-      if (Offset.isValid() &&
-          !Offset.hasSymbolicOffset() &&
+      if (Offset.isValid() && !Offset.hasSymbolicOffset() &&
           Offset.getOffset() != 0) {
         const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
         HandleOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
@@ -2365,9 +2369,8 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr 
*ArgExpr,
 
   // Normal free.
   if (Hold)
-    return State->set<RegionState>(SymBase,
-                                   RefState::getRelinquished(Family,
-                                                             ParentExpr));
+    return State->set<RegionState>(
+        SymBase, RefState::getRelinquished(Family, ParentExpr));
 
   return State->set<RegionState>(SymBase,
                                  RefState::getReleased(Family, ParentExpr));
@@ -2606,12 +2609,12 @@ void 
MallocChecker::HandleMismatchedDealloc(CheckerContext &C,
         os << " allocated by " << AllocOs.str();
 
       os << " should be deallocated by ";
-        printExpectedDeallocName(os, RS->getAllocationFamily());
+      printExpectedDeallocName(os, RS->getAllocationFamily());
 
-        if (printMemFnName(DeallocOs, C, DeallocExpr))
-          os << ", not " << DeallocOs.str();
+      if (printMemFnName(DeallocOs, C, DeallocExpr))
+        os << ", not " << DeallocOs.str();
 
-        printOwnershipTakesList(os, C, DeallocExpr);
+      printOwnershipTakesList(os, C, DeallocExpr);
     }
 
     auto R = std::make_unique<PathSensitiveBugReport>(
@@ -2648,8 +2651,7 @@ void MallocChecker::HandleOffsetFree(CheckerContext &C, 
SVal ArgVal,
   assert(MR && "Only MemRegion based symbols can have offset free errors");
 
   RegionOffset Offset = MR->getAsOffset();
-  assert((Offset.isValid() &&
-          !Offset.hasSymbolicOffset() &&
+  assert((Offset.isValid() && !Offset.hasSymbolicOffset() &&
           Offset.getOffset() != 0) &&
          "Only symbols with a valid offset can have offset free errors");
 
@@ -2658,11 +2660,8 @@ void MallocChecker::HandleOffsetFree(CheckerContext &C, 
SVal ArgVal,
   os << "Argument to ";
   if (!printMemFnName(os, C, DeallocExpr))
     os << "deallocator";
-  os << " is offset by "
-     << offsetBytes
-     << " "
-     << ((abs(offsetBytes) > 1) ? "bytes" : "byte")
-     << " from the start of ";
+  os << " is offset by " << offsetBytes << " "
+     << ((abs(offsetBytes) > 1) ? "bytes" : "byte") << " from the start of ";
   if (AllocExpr && printMemFnName(AllocNameOs, C, AllocExpr))
     os << "memory allocated by " << AllocNameOs.str();
   else
@@ -2892,8 +2891,8 @@ MallocChecker::ReallocMemAux(CheckerContext &C, const 
CallEvent &Call,
 
     // Record the info about the reallocated symbol so that we could properly
     // process failed reallocation.
-    stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
-                                                   ReallocPair(FromPtr, Kind));
+    stateRealloc =
+        stateRealloc->set<ReallocPairs>(ToPtr, ReallocPair(FromPtr, Kind));
     // The reallocated symbol should stay alive for as long as the new symbol.
     C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
     return stateRealloc;
@@ -2951,8 +2950,7 @@ MallocChecker::LeakInfo 
MallocChecker::getAllocationSite(const ExplodedNode *N,
     // Allocation node, is the last node in the current or parent context in
     // which the symbol was tracked.
     const LocationContext *NContext = N->getLocationContext();
-    if (NContext == LeakContext ||
-        NContext->isParentOf(LeakContext))
+    if (NContext == LeakContext || NContext->isParentOf(LeakContext))
       AllocNode = N;
     N = N->pred_empty() ? nullptr : *(N->pred_begin());
   }
@@ -2988,9 +2986,8 @@ void MallocChecker::HandleLeak(SymbolRef Sym, 
ExplodedNode *N,
 
   const Stmt *AllocationStmt = AllocNode->getStmtForDiagnostics();
   if (AllocationStmt)
-    LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocationStmt,
-                                              C.getSourceManager(),
-                                              AllocNode->getLocationContext());
+    LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
+        AllocationStmt, C.getSourceManager(), AllocNode->getLocationContext());
 
   SmallString<200> buf;
   llvm::raw_svector_ostream os(buf);
@@ -3012,8 +3009,7 @@ void MallocChecker::HandleLeak(SymbolRef Sym, 
ExplodedNode *N,
 }
 
 void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
-                                     CheckerContext &C) const
-{
+                                     CheckerContext &C) const {
   ProgramStateRef state = C.getState();
   RegionStateTy OldRS = state->get<RegionState>();
   RegionStateTy::Factory &F = state->get_context<RegionState>();
@@ -3031,8 +3027,7 @@ void MallocChecker::checkDeadSymbols(SymbolReaper 
&SymReaper,
 
   if (RS == OldRS) {
     // We shouldn't have touched other maps yet.
-    assert(state->get<ReallocPairs>() ==
-           C.getState()->get<ReallocPairs>());
+    assert(state->get<ReallocPairs>() == C.getState()->get<ReallocPairs>());
     assert(state->get<FreeReturnValue>() ==
            C.getState()->get<FreeReturnValue>());
     return;
@@ -3074,6 +3069,43 @@ void MallocChecker::checkPostCall(const CallEvent &Call,
     (*PostFN)(this, C.getState(), Call, C);
     return;
   }
+
+  ProgramStateRef State = C.getState();
+
+  if (const auto *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
+    // Ensure we are constructing a concrete object/subobject.
+    if (const MemRegion *ObjUnderConstr = Ctor->getCXXThisVal().getAsRegion()) 
{
+      ProgramStateRef NewState = State;
+
+      for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) {
+        SVal ArgV = Call.getArgSVal(I);
+
+        SymbolRef Sym = ArgV.getAsSymbol();
+        if (!Sym)
+          continue;
+
+        // Look up current ref-state for this symbol in the RegionState map.
+        if (const RefState *RS = State->get<RegionState>(Sym)) {
+          // Only re-label symbols that are still owned allocations from C++
+          // new/new[].
+          if (RS->isAllocated() &&
+              (RS->getAllocationFamily().Kind == AF_CXXNew ||
+               RS->getAllocationFamily().Kind == AF_CXXNewArray)) {
+
+            // Mark as Relinquished at the constructor site: ownership moves
+            // into the constructed subobject. Pass the ctor's origin expr as
+            // the statement associated with this transition.
+            NewState = NewState->set<RegionState>(
+                Sym, RefState::getRelinquished(RS->getAllocationFamily(),
+                                               Ctor->getOriginExpr()));
+          }
+        }
+      }
+
+      if (NewState != State)
+        C.addTransition(NewState);
+    }
+  }
 }
 
 void MallocChecker::checkPreCall(const CallEvent &Call,
@@ -3165,8 +3197,7 @@ void MallocChecker::checkPreCall(const CallEvent &Call,
   }
 }
 
-void MallocChecker::checkPreStmt(const ReturnStmt *S,
-                                 CheckerContext &C) const {
+void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const 
{
   checkEscapeOnReturn(S, C);
 }
 
@@ -3198,7 +3229,7 @@ void MallocChecker::checkEscapeOnReturn(const ReturnStmt 
*S,
     if (const MemRegion *MR = RetVal.getAsRegion())
       if (isa<FieldRegion, ElementRegion>(MR))
         if (const SymbolicRegion *BMR =
-              dyn_cast<SymbolicRegion>(MR->getBaseRegion()))
+                dyn_cast<SymbolicRegion>(MR->getBaseRegion()))
           Sym = BMR->getSymbol();
 
   // Check if we are returning freed memory.
@@ -3218,14 +3249,13 @@ void MallocChecker::checkPostStmt(const BlockExpr *BE,
     return;
 
   ProgramStateRef state = C.getState();
-  const BlockDataRegion *R =
-    cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());
+  const BlockDataRegion *R = 
cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());
 
   auto ReferencedVars = R->referenced_vars();
   if (ReferencedVars.empty())
     return;
 
-  SmallVector<const MemRegion*, 10> Regions;
+  SmallVector<const MemRegion *, 10> Regions;
   const LocationContext *LC = C.getLocationContext();
   MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
 
@@ -3237,8 +3267,7 @@ void MallocChecker::checkPostStmt(const BlockExpr *BE,
     Regions.push_back(VR);
   }
 
-  state =
-    state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
+  state = 
state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
   C.addTransition(state);
 }
 
@@ -3295,8 +3324,7 @@ void MallocChecker::checkUseZeroAllocated(SymbolRef Sym, 
CheckerContext &C,
   if (const RefState *RS = C.getState()->get<RegionState>(Sym)) {
     if (RS->isAllocatedOfSizeZero())
       HandleUseZeroAlloc(C, RS->getStmt()->getSourceRange(), Sym);
-  }
-  else if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
+  } else if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
     HandleUseZeroAlloc(C, S->getSourceRange(), Sym);
   }
 }
@@ -3313,9 +3341,8 @@ void MallocChecker::checkLocation(SVal l, bool isLoad, 
const Stmt *S,
 
 // If a symbolic region is assumed to NULL (or another constant), stop tracking
 // it - assuming that allocation failed on this path.
-ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
-                                              SVal Cond,
-                                              bool Assumption) const {
+ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state, SVal Cond,
+                                          bool Assumption) const {
   RegionStateTy RS = state->get<RegionState>();
   for (SymbolRef Sym : llvm::make_first_range(RS)) {
     // If the symbol is assumed to be NULL, remove it from consideration.
@@ -3340,7 +3367,8 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef 
state,
       if (RS->isReleased()) {
         switch (ReallocPair.Kind) {
         case OAR_ToBeFreedAfterFailure:
-          state = state->set<RegionState>(ReallocSym,
+          state = state->set<RegionState>(
+              ReallocSym,
               RefState::getAllocated(RS->getAllocationFamily(), 
RS->getStmt()));
           break;
         case OAR_DoNotTrackAfterFailure:
@@ -3358,9 +3386,8 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef 
state,
 }
 
 bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
-                                              const CallEvent *Call,
-                                              ProgramStateRef State,
-                                              SymbolRef &EscapingSymbol) const 
{
+    const CallEvent *Call, ProgramStateRef State,
+    SymbolRef &EscapingSymbol) const {
   assert(Call);
   EscapingSymbol = nullptr;
 
@@ -3470,8 +3497,8 @@ bool 
MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
   // Do not warn on pointers passed to 'setbuf' when used with std streams,
   // these leaks might be intentional when setting the buffer for stdio.
   // http://stackoverflow.com/questions/2671151/who-frees-setvbuf-buffer
-  if (FName == "setbuf" || FName =="setbuffer" ||
-      FName == "setlinebuf" || FName == "setvbuf") {
+  if (FName == "setbuf" || FName == "setbuffer" || FName == "setlinebuf" ||
+      FName == "setvbuf") {
     if (Call->getNumArgs() >= 1) {
       const Expr *ArgE = Call->getArgExpr(0)->IgnoreParenCasts();
       if (const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
@@ -3521,18 +3548,16 @@ bool 
MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
   return false;
 }
 
-ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State,
-                                             const InvalidatedSymbols &Escaped,
-                                             const CallEvent *Call,
-                                             PointerEscapeKind Kind) const {
+ProgramStateRef MallocChecker::checkPointerEscape(
+    ProgramStateRef State, const InvalidatedSymbols &Escaped,
+    const CallEvent *Call, PointerEscapeKind Kind) const {
   return checkPointerEscapeAux(State, Escaped, Call, Kind,
                                /*IsConstPointerEscape*/ false);
 }
 
-ProgramStateRef MallocChecker::checkConstPointerEscape(ProgramStateRef State,
-                                              const InvalidatedSymbols 
&Escaped,
-                                              const CallEvent *Call,
-                                              PointerEscapeKind Kind) const {
+ProgramStateRef MallocChecker::checkConstPointerEscape(
+    ProgramStateRef State, const InvalidatedSymbols &Escaped,
+    const CallEvent *Call, PointerEscapeKind Kind) const {
   // If a const pointer escapes, it may not be freed(), but it could be 
deleted.
   return checkPointerEscapeAux(State, Escaped, Call, Kind,
                                /*IsConstPointerEscape*/ true);
@@ -3724,61 +3749,61 @@ PathDiagnosticPieceRef 
MallocBugVisitor::VisitNode(const ExplodedNode *N,
         }
         Msg = OS.str();
         break;
-        }
-        case AF_None:
-          assert(false && "Unhandled allocation family!");
-          return nullptr;
-        }
+      }
+      case AF_None:
+        assert(false && "Unhandled allocation family!");
+        return nullptr;
+      }
 
-        // Record the stack frame that is _responsible_ for this memory release
-        // event. This will be used by the false positive suppression 
heuristics
-        // that recognize the release points of reference-counted objects.
-        //
-        // Usually (e.g. in C) we say that the _responsible_ stack frame is the
...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/155131
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to