@@ -437,6 +437,10 @@ class RegionStoreManager : public StoreManager {
437
437
438
438
RegionBindingsRef removeSubRegionBindings (RegionBindingsConstRef B,
439
439
const SubRegion *R);
440
+ Optional<SVal> getConstantValFromConstArrayInitializer (
441
+ RegionBindingsConstRef B, const VarRegion *VR, const ElementRegion *R);
442
+ Optional<SVal> getSValFromInitListExpr (const InitListExpr *ILE,
443
+ uint64_t Offset, QualType ElemT);
440
444
441
445
public: // Part of public interface to class.
442
446
@@ -1625,6 +1629,105 @@ RegionStoreManager::findLazyBinding(RegionBindingsConstRef B,
1625
1629
return Result;
1626
1630
}
1627
1631
1632
+ Optional<SVal> RegionStoreManager::getConstantValFromConstArrayInitializer (
1633
+ RegionBindingsConstRef B, const VarRegion *VR, const ElementRegion *R) {
1634
+ assert (R && VR && " Regions should not be null" );
1635
+
1636
+ // Check if the containing array has an initialized value that we can trust.
1637
+ // We can trust a const value or a value of a global initializer in main().
1638
+ const VarDecl *VD = VR->getDecl ();
1639
+ if (!VD->getType ().isConstQualified () &&
1640
+ !R->getElementType ().isConstQualified () &&
1641
+ (!B.isMainAnalysis () || !VD->hasGlobalStorage ()))
1642
+ return None;
1643
+
1644
+ // Array's declaration should have `ConstantArrayType` type, because only this
1645
+ // type contains an array extent. It may happen that array type can be of
1646
+ // `IncompleteArrayType` type. To get the declaration of `ConstantArrayType`
1647
+ // type, we should find the declaration in the redeclarations chain that has
1648
+ // the initialization expression.
1649
+ // NOTE: `getAnyInitializer` has an out-parameter, which returns a new `VD`
1650
+ // from which an initializer is obtained. We replace current `VD` with the new
1651
+ // `VD`. If the return value of the function is null than `VD` won't be
1652
+ // replaced.
1653
+ const Expr *Init = VD->getAnyInitializer (VD);
1654
+ // NOTE: If `Init` is non-null, then a new `VD` is non-null for sure. So check
1655
+ // `Init` for null only and don't worry about the replaced `VD`.
1656
+ if (!Init)
1657
+ return None;
1658
+
1659
+ // Array's declaration should have ConstantArrayType type, because only this
1660
+ // type contains an array extent.
1661
+ const ConstantArrayType *CAT = Ctx.getAsConstantArrayType (VD->getType ());
1662
+ if (!CAT)
1663
+ return None;
1664
+
1665
+ // Array should be one-dimensional.
1666
+ // TODO: Support multidimensional array.
1667
+ if (isa<ConstantArrayType>(CAT->getElementType ())) // is multidimensional
1668
+ return None;
1669
+
1670
+ // Array's offset should be a concrete value.
1671
+ // Return Unknown value if symbolic index presented.
1672
+ // FIXME: We also need to take ElementRegions with symbolic
1673
+ // indexes into account.
1674
+ const auto OffsetVal = R->getIndex ().getAs <nonloc::ConcreteInt>();
1675
+ if (!OffsetVal.hasValue ())
1676
+ return UnknownVal ();
1677
+
1678
+ // Check offset for being out of bounds.
1679
+ // C++20 [expr.add] 7.6.6.4 (excerpt):
1680
+ // If P points to an array element i of an array object x with n
1681
+ // elements, where i < 0 or i > n, the behavior is undefined.
1682
+ // Dereferencing is not allowed on the "one past the last
1683
+ // element", when i == n.
1684
+ // Example:
1685
+ // const int arr[4] = {1, 2};
1686
+ // const int *ptr = arr;
1687
+ // int x0 = ptr[0]; // 1
1688
+ // int x1 = ptr[1]; // 2
1689
+ // int x2 = ptr[2]; // 0
1690
+ // int x3 = ptr[3]; // 0
1691
+ // int x4 = ptr[4]; // UB
1692
+ // int x5 = ptr[-1]; // UB
1693
+ const llvm::APSInt &OffsetInt = OffsetVal->getValue ();
1694
+ const auto Offset = static_cast <uint64_t >(OffsetInt.getExtValue ());
1695
+ // Use `getZExtValue` because array extent can not be negative.
1696
+ const uint64_t Extent = CAT->getSize ().getZExtValue ();
1697
+ // Check for `OffsetInt < 0` but NOT for `Offset < 0`, because `OffsetInt`
1698
+ // CAN be negative, but `Offset` can NOT, because `Offset` is an uint64_t.
1699
+ if (OffsetInt < 0 || Offset >= Extent)
1700
+ return UndefinedVal ();
1701
+ // From here `Offset` is in the bounds.
1702
+
1703
+ // Handle InitListExpr.
1704
+ if (const auto *ILE = dyn_cast<InitListExpr>(Init))
1705
+ return getSValFromInitListExpr (ILE, Offset, R->getElementType ());
1706
+
1707
+ // FIXME: Handle StringLiteral.
1708
+
1709
+ // FIXME: Handle CompoundLiteralExpr.
1710
+
1711
+ return None;
1712
+ }
1713
+
1714
+ Optional<SVal>
1715
+ RegionStoreManager::getSValFromInitListExpr (const InitListExpr *ILE,
1716
+ uint64_t Offset, QualType ElemT) {
1717
+ assert (ILE && " InitListExpr should not be null" );
1718
+
1719
+ // C++20 [expr.add] 9.4.17.5 (excerpt):
1720
+ // i-th array element is value-initialized for each k < i ≤ n,
1721
+ // where k is an expression-list size and n is an array extent.
1722
+ if (Offset >= ILE->getNumInits ())
1723
+ return svalBuilder.makeZeroVal (ElemT);
1724
+
1725
+ // Return a constant value, if it is presented.
1726
+ // FIXME: Support other SVals.
1727
+ const Expr *E = ILE->getInit (Offset);
1728
+ return svalBuilder.getConstantVal (E);
1729
+ }
1730
+
1628
1731
SVal RegionStoreManager::getBindingForElement (RegionBindingsConstRef B,
1629
1732
const ElementRegion* R) {
1630
1733
// Check if the region has a binding.
@@ -1658,64 +1761,8 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
1658
1761
return svalBuilder.makeIntVal (c, T);
1659
1762
}
1660
1763
} else if (const VarRegion *VR = dyn_cast<VarRegion>(superR)) {
1661
- // Check if the containing array has an initialized value that we can trust.
1662
- // We can trust a const value or a value of a global initializer in main().
1663
- const VarDecl *VD = VR->getDecl ();
1664
- if (VD->getType ().isConstQualified () ||
1665
- R->getElementType ().isConstQualified () ||
1666
- (B.isMainAnalysis () && VD->hasGlobalStorage ())) {
1667
- if (const Expr *Init = VD->getAnyInitializer ()) {
1668
- if (const auto *InitList = dyn_cast<InitListExpr>(Init)) {
1669
- // The array index has to be known.
1670
- if (auto CI = R->getIndex ().getAs <nonloc::ConcreteInt>()) {
1671
- // If it is not an array, return Undef.
1672
- QualType T = VD->getType ();
1673
- const ConstantArrayType *CAT = Ctx.getAsConstantArrayType (T);
1674
- if (!CAT)
1675
- return UndefinedVal ();
1676
-
1677
- // Support one-dimensional array.
1678
- // C++20 [expr.add] 7.6.6.4 (excerpt):
1679
- // If P points to an array element i of an array object x with n
1680
- // elements, where i < 0 or i > n, the behavior is undefined.
1681
- // Dereferencing is not allowed on the "one past the last
1682
- // element", when i == n.
1683
- // Example:
1684
- // const int arr[4] = {1, 2};
1685
- // const int *ptr = arr;
1686
- // int x0 = ptr[0]; // 1
1687
- // int x1 = ptr[1]; // 2
1688
- // int x2 = ptr[2]; // 0
1689
- // int x3 = ptr[3]; // 0
1690
- // int x4 = ptr[4]; // UB
1691
- // TODO: Support multidimensional array.
1692
- if (!isa<ConstantArrayType>(CAT->getElementType ())) {
1693
- // One-dimensional array.
1694
- const llvm::APSInt &Idx = CI->getValue ();
1695
- const auto I = static_cast <uint64_t >(Idx.getExtValue ());
1696
- // Use `getZExtValue` because array extent can not be negative.
1697
- const uint64_t Extent = CAT->getSize ().getZExtValue ();
1698
- // Check for `Idx < 0`, NOT for `I < 0`, because `Idx` CAN be
1699
- // negative, but `I` can NOT.
1700
- if (Idx < 0 || I >= Extent)
1701
- return UndefinedVal ();
1702
-
1703
- // C++20 [expr.add] 9.4.17.5 (excerpt):
1704
- // i-th array element is value-initialized for each k < i ≤ n,
1705
- // where k is an expression-list size and n is an array extent.
1706
- if (I >= InitList->getNumInits ())
1707
- return svalBuilder.makeZeroVal (R->getElementType ());
1708
-
1709
- // Return a constant value, if it is presented.
1710
- // FIXME: Support other SVals.
1711
- const Expr *E = InitList->getInit (I);
1712
- if (Optional<SVal> V = svalBuilder.getConstantVal (E))
1713
- return *V;
1714
- }
1715
- }
1716
- }
1717
- }
1718
- }
1764
+ if (Optional<SVal> V = getConstantValFromConstArrayInitializer (B, VR, R))
1765
+ return *V;
1719
1766
}
1720
1767
1721
1768
// Check for loads from a code text region. For such loads, just give up.
0 commit comments