[PATCH] D107339: [analyzer] Retrieve a character from StringLiteral as an initializer for constant arrays.

Denys Petrov via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 12 13:09:16 PDT 2021


ASDenysPetrov updated this revision to Diff 366083.
ASDenysPetrov added a comment.

Rebased.


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

https://reviews.llvm.org/D107339

Files:
  clang/lib/StaticAnalyzer/Core/RegionStore.cpp


Index: clang/lib/StaticAnalyzer/Core/RegionStore.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -443,6 +443,8 @@
   Optional<SVal> getSValFromInitListExprByIndex(const InitListExpr *ILE,
                                                 const llvm::APSInt &Idx,
                                                 QualType ElemT);
+  SVal getSValFromStringLiteralByIndex(const StringLiteral *SL,
+                                       const llvm::APSInt &Idx, QualType ElemT);
 
 public: // Part of public interface to class.
 
@@ -1649,7 +1651,9 @@
   if (const auto *ILE = dyn_cast<InitListExpr>(Init))
     return getSValFromInitListExprByIndex(ILE, Idx, ElemT);
 
-  // FIXME: Handle StringLiteral.
+  // Handle StringLiteral.
+  if (const auto *SL = dyn_cast<StringLiteral>(Init))
+    return getSValFromStringLiteralByIndex(SL, Idx, ElemT);
 
   // FIXME: Handle CompoundLiteralExpr.
 
@@ -1679,6 +1683,22 @@
   return svalBuilder.getConstantVal(E);
 }
 
+SVal RegionStoreManager::getSValFromStringLiteralByIndex(
+    const StringLiteral *SL, const llvm::APSInt &Idx, QualType ElemT) {
+  assert(SL && "StringLiteral should not be null");
+  // If index is out of bounds, return Undef.
+  const int64_t I = Idx.getExtValue();
+  if (Idx.isSigned() && I < 0)
+    return UndefinedVal();
+  // Technically, only i == length is guaranteed to be null.
+  // However, such overflows should be caught before reaching this point;
+  // the only time such an access would be made is if a string literal was
+  // used to initialize a larger array.
+  uint32_t Code =
+      (static_cast<uint64_t>(I) >= SL->getLength()) ? 0 : SL->getCodeUnit(I);
+  return svalBuilder.makeIntVal(Code, ElemT);
+}
+
 SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
                                               const ElementRegion* R) {
   // Check if the region has a binding.
@@ -1695,21 +1715,10 @@
     if (!Ctx.hasSameUnqualifiedType(T, R->getElementType()))
       return UnknownVal();
 
-    const StringLiteral *Str = StrR->getStringLiteral();
     SVal Idx = R->getIndex();
     if (Optional<nonloc::ConcreteInt> CI = Idx.getAs<nonloc::ConcreteInt>()) {
-      int64_t i = CI->getValue().getSExtValue();
-      // Abort on string underrun.  This can be possible by arbitrary
-      // clients of getBindingForElement().
-      if (i < 0)
-        return UndefinedVal();
-      int64_t length = Str->getLength();
-      // Technically, only i == length is guaranteed to be null.
-      // However, such overflows should be caught before reaching this point;
-      // the only time such an access would be made is if a string literal was
-      // used to initialize a larger array.
-      char c = (i >= length) ? '\0' : Str->getCodeUnit(i);
-      return svalBuilder.makeIntVal(c, T);
+      const StringLiteral *Str = StrR->getStringLiteral();
+      return getSValFromStringLiteralByIndex(Str, CI->getValue(), T);
     }
   } else if (isa<ElementRegion>(superR) || isa<VarRegion>(superR)) {
     const VarRegion *VR = nullptr;
@@ -2237,10 +2246,11 @@
 RegionBindingsRef RegionStoreManager::bindArray(RegionBindingsConstRef B,
                                                 const TypedValueRegion *R,
                                                 SVal Init) {
-  // Ignore binding `InitListExpr` to arrays of const type,
-  // since we can directly retrieve values from initializer using
+  // Ignore binding `InitListExpr` and `StringLiteral` to arrays of const type,
+  // since we can directly retrieve values from initializers using
   // `getConstantValFromConstArrayInitializer`.For example:
   //   const int arr[42] = { 1, 2, 3 };
+  //   const char arr[42] = "123";
   // The init values of this array will never change, so we don't have to
   // store them additionally in the RegionStore.
   if (const auto *VR = dyn_cast<VarRegion>(R)) {
@@ -2248,9 +2258,9 @@
     // Ignore only arrays which values can't change.
     if (VD->getType().isConstQualified()) {
       const Expr *Init = VD->getAnyInitializer();
-      // FIXME: Ignore `StringLiteral` and `CompoundLiteralExpr` as well when
-      // `getConstantValFromConstArrayInitializer` supports them.
-      if (isa_and_nonnull<InitListExpr>(Init))
+      // FIXME: Ignore `CompoundLiteralExpr` as well when
+      // `getConstantValFromConstArrayInitializer` supports it.
+      if (Init && (isa<InitListExpr>(Init) || isa<StringLiteral>(Init)))
         return B;
     }
   }


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D107339.366083.patch
Type: text/x-patch
Size: 4592 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20210812/944a5d51/attachment-0001.bin>


More information about the cfe-commits mailing list