Index: clang/lib/StaticAnalyzer/Core/RegionStore.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -443,6 +443,8 @@ Optional 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(Init)) return getSValFromInitListExprByIndex(ILE, Idx, ElemT); - // FIXME: Handle StringLiteral. + // Handle StringLiteral. + if (const auto *SL = dyn_cast(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(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 CI = Idx.getAs()) { - 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(superR) || isa(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(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(Init)) + // FIXME: Ignore `CompoundLiteralExpr` as well when + // `getConstantValFromConstArrayInitializer` supports it. + if (Init && (isa(Init) || isa(Init))) return B; } }