Charusso updated this revision to Diff 227534.
Charusso marked 6 inline comments as done.
Charusso added a comment.

- Fix.


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

https://reviews.llvm.org/D69726

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSizeInfo.h
  clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
  clang/lib/StaticAnalyzer/Core/DynamicSize.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp

Index: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -10,7 +10,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
 #include "PrettyStackTraceLocationContext.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/DeclCXX.h"
@@ -18,6 +17,8 @@
 #include "clang/Analysis/ConstructionContext.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Support/SaveAndRestore.h"
@@ -653,16 +654,21 @@
 
     // See if we need to conjure a heap pointer instead of
     // a regular unknown pointer.
-    bool IsHeapPointer = false;
-    if (const auto *CNE = dyn_cast<CXXNewExpr>(E))
-      if (CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) {
-        // FIXME: Delegate this to evalCall in MallocChecker?
-        IsHeapPointer = true;
+    const auto *CNE = dyn_cast<CXXNewExpr>(E);
+    if (CNE && CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) {
+      // FIXME: Delegate this to evalCall in MallocChecker?
+      DefinedOrUnknownSVal Size = UnknownVal();
+      const Expr *SizeExpr = nullptr;
+
+      if ((SizeExpr = CNE->getArraySize().getValueOr(nullptr))) {
+        Size = State->getSVal(SizeExpr, LCtx).castAs<DefinedOrUnknownSVal>();
       }
 
-    R = IsHeapPointer ? svalBuilder.getConjuredHeapSymbolVal(E, LCtx, Count)
-                      : svalBuilder.conjureSymbolVal(nullptr, E, LCtx, ResultTy,
-                                                     Count);
+      R = svalBuilder.getConjuredHeapSymbolVal(E, LCtx, Count);
+      State = setDynamicSize(State, R.getAsRegion(), Size, SizeExpr);
+    } else {
+      R = svalBuilder.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count);
+    }
   }
   return State->BindExpr(E, LCtx, R);
 }
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -10,15 +10,16 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/Analysis/ConstructionContext.h"
 #include "clang/AST/DeclCXX.h"
-#include "clang/AST/StmtCXX.h"
 #include "clang/AST/ParentMap.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Analysis/ConstructionContext.h"
 #include "clang/Basic/PrettyStackTrace.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
 
 using namespace clang;
 using namespace ento;
@@ -761,11 +762,20 @@
   // heap. We realize this is an approximation that might not correctly model
   // a custom global allocator.
   if (symVal.isUnknown()) {
-    if (IsStandardGlobalOpNewFunction)
+    if (IsStandardGlobalOpNewFunction) {
+      DefinedOrUnknownSVal Size = UnknownVal();
+      const Expr *SizeExpr = nullptr;
+
+      if ((SizeExpr = CNE->getArraySize().getValueOr(nullptr))) {
+        Size = State->getSVal(SizeExpr, LCtx).castAs<DefinedOrUnknownSVal>();
+      }
+
       symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount);
-    else
+      State = setDynamicSize(State, symVal.getAsRegion(), Size, SizeExpr);
+    } else {
       symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, LCtx, CNE->getType(),
                                             blockCount);
+    }
   }
 
   CallEventManager &CEMgr = getStateManager().getCallEventManager();
Index: clang/lib/StaticAnalyzer/Core/DynamicSize.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/DynamicSize.cpp
+++ clang/lib/StaticAnalyzer/Core/DynamicSize.cpp
@@ -13,20 +13,40 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h"
 #include "clang/AST/Expr.h"
 #include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSizeInfo.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
 
+REGISTER_MAP_WITH_PROGRAMSTATE(DynamicSizeMap, const clang::ento::MemRegion *,
+                               clang::ento::DynamicSizeInfo)
+
 namespace clang {
 namespace ento {
 
+ProgramStateRef setDynamicSize(ProgramStateRef State, const MemRegion *MR,
+                               DefinedOrUnknownSVal Size,
+                               const Expr *SizeExpr) {
+  return State->set<DynamicSizeMap>(MR, {Size, SizeExpr});
+}
+
 DefinedOrUnknownSVal getDynamicSize(ProgramStateRef State, const MemRegion *MR,
                                     SValBuilder &SVB) {
+  if (const DynamicSizeInfo *SizeInfo = State->get<DynamicSizeMap>(MR))
+    return SizeInfo->getSize();
+
   return MR->getMemRegionManager().getStaticSize(MR, SVB);
 }
 
+const Expr *getDynamicSizeExpr(ProgramStateRef State, const MemRegion *MR) {
+  if (const DynamicSizeInfo *SizeInfo = State->get<DynamicSizeMap>(MR))
+    return SizeInfo->getSizeExpr();
+
+  return nullptr;
+}
+
 DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State,
                                             const MemRegion *MR,
                                             SValBuilder &SVB,
Index: clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -166,18 +166,9 @@
   SVal ArraySizeVal = svalBuilder.evalBinOpNN(
       state, BO_Mul, ArrayLength, EleSizeVal.castAs<NonLoc>(), SizeTy);
 
-  // Finally, assume that the array's size matches the given size.
-  const LocationContext *LC = C.getLocationContext();
-  DefinedOrUnknownSVal DynSize =
-      getDynamicSize(state, state->getRegion(VD, LC), svalBuilder);
-
-  DefinedOrUnknownSVal ArraySize = ArraySizeVal.castAs<DefinedOrUnknownSVal>();
-  DefinedOrUnknownSVal sizeIsKnown =
-      svalBuilder.evalEQ(state, DynSize, ArraySize);
-  state = state->assume(sizeIsKnown, true);
-
-  // Assume should not fail at this point.
-  assert(state);
+  // Finally, set the size.
+  state = setDynamicSize(state, state->getRegion(VD, C.getLocationContext()),
+                         ArraySizeVal.castAs<DefinedOrUnknownSVal>(), SE);
 
   // Remember our assumptions!
   C.addTransition(state);
Index: clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -441,29 +441,30 @@
   /// Models memory allocation.
   ///
   /// \param [in] CE The expression that allocates memory.
-  /// \param [in] SizeEx Size of the memory that needs to be allocated.
+  /// \param [in] SizeExpr Size of the memory that needs to be allocated.
   /// \param [in] Init The value the allocated memory needs to be initialized.
   /// with. For example, \c calloc initializes the allocated memory to 0,
   /// malloc leaves it undefined.
   /// \param [in] State The \c ProgramState right before allocation.
   /// \returns The ProgramState right after allocation.
   static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
-                                      const Expr *SizeEx, SVal Init,
+                                      const Expr *SizeExpr, SVal Init,
                                       ProgramStateRef State,
                                       AllocationFamily Family = AF_Malloc);
 
   /// Models memory allocation.
   ///
   /// \param [in] CE The expression that allocates memory.
-  /// \param [in] Size Size of the memory that needs to be allocated.
+  /// \param [in] Size Symbolic size of the memory that needs to be allocated.
+  /// \param [in] SizeExpr Size expression of the memory allocation.
   /// \param [in] Init The value the allocated memory needs to be initialized.
   /// with. For example, \c calloc initializes the allocated memory to 0,
   /// malloc leaves it undefined.
   /// \param [in] State The \c ProgramState right before allocation.
   /// \returns The ProgramState right after allocation.
   static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
-                                      SVal Size, SVal Init,
-                                      ProgramStateRef State,
+                                      const Expr *SizeExpr, SVal Size,
+                                      SVal Init, ProgramStateRef State,
                                       AllocationFamily Family = AF_Malloc);
 
   static ProgramStateRef addExtentSize(CheckerContext &C, const CXXNewExpr *NE,
@@ -1163,8 +1164,8 @@
     } else if (FunI == MemFunctionInfo.II_if_nameindex) {
       // Should we model this differently? We can allocate a fixed number of
       // elements with zeros in the last one.
-      State = MallocMemAux(C, CE, UnknownVal(), UnknownVal(), State,
-                           AF_IfNameIndex);
+      State = MallocMemAux(C, CE, /*SizeExpr=*/nullptr, UnknownVal(),
+                           UnknownVal(), State, AF_IfNameIndex);
     } else if (FunI == MemFunctionInfo.II_if_freenameindex) {
       State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory);
     } else if (FunI == MemFunctionInfo.II_g_malloc0 ||
@@ -1193,7 +1194,8 @@
         Init = SB.makeZeroVal(SB.getContext().CharTy);
       }
       SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1));
-      State = MallocMemAux(C, CE, TotalSize, Init, State);
+      State = MallocMemAux(C, CE, /*SizeExpr=*/CE->getArg(0), TotalSize, Init,
+                           State);
       State = ProcessZeroAllocCheck(C, CE, 0, State);
       State = ProcessZeroAllocCheck(C, CE, 1, State);
     } else if (FunI == MemFunctionInfo.II_g_realloc_n ||
@@ -1403,16 +1405,15 @@
   CharUnits TypeSize = AstContext.getTypeSizeInChars(ElementType);
 
   if (ElementCount.getAs<NonLoc>()) {
-    DefinedOrUnknownSVal DynSize = getDynamicSize(State, Region, svalBuilder);
-
     // size in Bytes = ElementCount*TypeSize
     SVal SizeInBytes = svalBuilder.evalBinOpNN(
         State, BO_Mul, ElementCount.castAs<NonLoc>(),
         svalBuilder.makeArrayIndex(TypeSize.getQuantity()),
         svalBuilder.getArrayIndexType());
-    DefinedOrUnknownSVal DynSizeMatchesSize = svalBuilder.evalEQ(
-        State, DynSize, SizeInBytes.castAs<DefinedOrUnknownSVal>());
-    State = State->assume(DynSizeMatchesSize, true);
+
+    State = setDynamicSize(State, Region,
+                           SizeInBytes.castAs<DefinedOrUnknownSVal>(),
+                           NE->getArraySize().getValueOr(nullptr));
   }
   return State;
 }
@@ -1495,25 +1496,27 @@
     return MallocMemAux(C, CE, CE->getArg(I->getASTIndex()), UndefinedVal(),
                         State);
   }
-  return MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), State);
+  return MallocMemAux(C, CE, /*SizeExpr=*/nullptr, UnknownVal(), UndefinedVal(),
+                      State);
 }
 
 ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
                                             const CallExpr *CE,
-                                            const Expr *SizeEx, SVal Init,
+                                            const Expr *SizeExpr, SVal Init,
                                             ProgramStateRef State,
                                             AllocationFamily Family) {
   if (!State)
     return nullptr;
 
-  return MallocMemAux(C, CE, C.getSVal(SizeEx), Init, State, Family);
+  return MallocMemAux(C, CE, SizeExpr, C.getSVal(SizeExpr), Init, State,
+                      Family);
 }
 
 ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
-                                           const CallExpr *CE,
-                                           SVal Size, SVal Init,
-                                           ProgramStateRef State,
-                                           AllocationFamily Family) {
+                                            const CallExpr *CE,
+                                            const Expr *SizeExpr, SVal Size,
+                                            SVal Init, ProgramStateRef State,
+                                            AllocationFamily Family) {
   if (!State)
     return nullptr;
 
@@ -1534,21 +1537,9 @@
   // Fill the region with the initialization value.
   State = State->bindDefaultInitial(RetVal, Init, LCtx);
 
-  // Set the region's extent equal to the Size parameter.
-  const SymbolicRegion *R =
-      dyn_cast_or_null<SymbolicRegion>(RetVal.getAsRegion());
-  if (!R)
-    return nullptr;
-  if (Optional<DefinedOrUnknownSVal> DefinedSize =
-          Size.getAs<DefinedOrUnknownSVal>()) {
-    DefinedOrUnknownSVal DynSize = getDynamicSize(State, R, svalBuilder);
-
-    DefinedOrUnknownSVal DynSizeMatchesSize =
-        svalBuilder.evalEQ(State, DynSize, *DefinedSize);
-
-    State = State->assume(DynSizeMatchesSize, true);
-    assert(State);
-  }
+  // Set the region's size.
+  State = setDynamicSize(State, RetVal.getAsRegion(),
+                         Size.castAs<DefinedOrUnknownSVal>(), SizeExpr);
 
   return MallocUpdateRefState(C, CE, State, Family);
 }
@@ -2442,8 +2433,8 @@
   // If the ptr is NULL and the size is not 0, the call is equivalent to
   // malloc(size).
   if (PrtIsNull && !SizeIsZero) {
-    ProgramStateRef stateMalloc = MallocMemAux(C, CE, TotalSize,
-                                               UndefinedVal(), StatePtrIsNull);
+    ProgramStateRef stateMalloc =
+        MallocMemAux(C, CE, Arg1, TotalSize, UndefinedVal(), StatePtrIsNull);
     return stateMalloc;
   }
 
@@ -2474,8 +2465,8 @@
   if (ProgramStateRef stateFree =
           FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocated)) {
 
-    ProgramStateRef stateRealloc = MallocMemAux(C, CE, TotalSize,
-                                                UnknownVal(), stateFree);
+    ProgramStateRef stateRealloc =
+        MallocMemAux(C, CE, Arg1, TotalSize, UnknownVal(), stateFree);
     if (!stateRealloc)
       return nullptr;
 
@@ -2508,7 +2499,7 @@
   SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
   SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1));
 
-  return MallocMemAux(C, CE, TotalSize, zeroVal, State);
+  return MallocMemAux(C, CE, CE->getArg(0), TotalSize, zeroVal, State);
 }
 
 MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,
Index: clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -90,12 +90,8 @@
     if (Size.isUndef())
       return true; // Return true to model purity.
 
-    SValBuilder& svalBuilder = C.getSValBuilder();
-    DefinedOrUnknownSVal DynSize = getDynamicSize(state, R, svalBuilder);
-    DefinedOrUnknownSVal DynSizeMatchesSizeArg =
-        svalBuilder.evalEQ(state, DynSize, Size.castAs<DefinedOrUnknownSVal>());
-    state = state->assume(DynSizeMatchesSizeArg, true);
-    assert(state && "The region should not have any previous constraints");
+    state = setDynamicSize(state, R, Size.castAs<DefinedOrUnknownSVal>(),
+                           Call.getArgExpr(0));
 
     C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
     return true;
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSizeInfo.h
===================================================================
--- /dev/null
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSizeInfo.h
@@ -0,0 +1,45 @@
+//===- DynamicSizeInfo.h - Runtime size information -------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICSIZEINFO_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICSIZEINFO_H
+
+namespace clang {
+namespace ento {
+
+#include "clang/AST/Expr.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+
+/// Helper class to store information about the dynamic size.
+class DynamicSizeInfo {
+public:
+  DynamicSizeInfo(DefinedOrUnknownSVal Size, const Expr *SizeExpr = nullptr)
+      : Size(Size), SizeExpr(SizeExpr) {}
+
+  DefinedOrUnknownSVal getSize() const { return Size; }
+  const Expr *getSizeExpr() const { return SizeExpr; }
+
+  bool operator==(const DynamicSizeInfo &RHS) const {
+    return Size == RHS.Size && SizeExpr == RHS.SizeExpr;
+  }
+
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    ID.Add(Size);
+    ID.AddPointer(SizeExpr);
+  }
+
+private:
+  DefinedOrUnknownSVal Size;
+  const Expr *SizeExpr;
+};
+
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICSIZEINFO_H
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h
@@ -22,16 +22,24 @@
 namespace clang {
 namespace ento {
 
-/// Get the stored dynamic size for the region \p MR.
+/// \returns The stored dynamic size for the region \p MR.
 DefinedOrUnknownSVal getDynamicSize(ProgramStateRef State, const MemRegion *MR,
                                     SValBuilder &SVB);
 
-/// Get the stored element count of the region \p MR.
+/// \returns The stored dynamic size expression for the region \p MR.
+const Expr *getDynamicSizeExpr(ProgramStateRef State, const MemRegion *MR);
+
+/// \returns The stored element count of the region \p MR.
 DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State,
                                             const MemRegion *MR,
                                             SValBuilder &SVB,
                                             QualType ElementTy);
 
+/// Set the dynamic size \p Size with its expression \p SizeExpr of the region
+/// \p MR.
+ProgramStateRef setDynamicSize(ProgramStateRef State, const MemRegion *MR,
+                               DefinedOrUnknownSVal Size, const Expr *SizeExpr);
+
 } // namespace ento
 } // namespace clang
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to