[clang] [analyzer] Refine invalidation caused by `fread` (PR #93408)

Balázs Kéri via cfe-commits cfe-commits at lists.llvm.org
Mon May 27 05:52:42 PDT 2024


================
@@ -717,18 +717,71 @@ const ExplodedNode *StreamChecker::getAcquisitionSite(const ExplodedNode *N,
   return nullptr;
 }
 
+/// Invalidate only the requested elements instead of the whole buffer.
+/// This is basically a refinement of the more generic 'escapeArgs' or
+/// the plain old 'invalidateRegions'.
+/// This only works if the \p StartIndex and \p Count are concrete or
+/// perfectly-constrained.
+static ProgramStateRef
+escapeByStartIndexAndCount(ProgramStateRef State, CheckerContext &C,
+                           const CallEvent &Call, const MemRegion *Buffer,
+                           QualType ElemType, SVal StartIndex, SVal Count) {
+  if (!llvm::isa_and_nonnull<SubRegion>(Buffer))
+    return State;
+
+  auto UnboxAsInt = [&C, &State](SVal V) -> std::optional<int64_t> {
+    auto &SVB = C.getSValBuilder();
+    if (const llvm::APSInt *Int = SVB.getKnownValue(State, V))
+      return Int->tryExtValue();
+    return std::nullopt;
+  };
+
+  auto StartIndexVal = UnboxAsInt(StartIndex);
+  auto CountVal = UnboxAsInt(Count);
+
+  // FIXME: Maybe we could make this more generic, and expose this by the
+  // 'invalidateRegions' API. After doing so, it might make sense to make this
+  // limit configurable.
+  constexpr int MaxInvalidatedElementsLimit = 64;
+  if (!StartIndexVal || !CountVal || *CountVal > MaxInvalidatedElementsLimit) {
+    return State->invalidateRegions({loc::MemRegionVal{Buffer}},
+                                    Call.getOriginExpr(), C.blockCount(),
+                                    C.getLocationContext(),
+                                    /*CausesPointerEscape=*/false);
+  }
+
+  constexpr auto DoNotInvalidateSuperRegion =
+      RegionAndSymbolInvalidationTraits::InvalidationKinds::
+          TK_DoNotInvalidateSuperRegion;
+
+  auto &RegionManager = Buffer->getMemRegionManager();
+  SmallVector<SVal> EscapingVals;
+  EscapingVals.reserve(*CountVal);
+
+  RegionAndSymbolInvalidationTraits ITraits;
+  for (auto Idx : llvm::seq(*StartIndexVal, *StartIndexVal + *CountVal)) {
----------------
balazske wrote:

This loop does not work if the type of the array is not the same as the "size" parameter passed to `fread`.:
```
int buffer[100];
fread(buffer + 1, 3, 5, file);
```
In this case 3*5 bytes should be read by `fread` into the array. If `sizeof(int)==4` 4 elements should be invalidated in the buffer starting from index 1.

https://github.com/llvm/llvm-project/pull/93408


More information about the cfe-commits mailing list