================ @@ -0,0 +1,163 @@ +//===- ContainerOfModeling.h ------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/ContainerOfModeling.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" + +namespace clang::ento { + +static QualType getRegionObjectType(const MemRegion *Region) { + if (const auto *TVR = dyn_cast<TypedValueRegion>(Region)) + return TVR->getValueType(); + if (const auto *SR = dyn_cast<SymbolicRegion>(Region)) + return SR->getPointeeStaticType(); + return {}; +} + +/// Return true when the region containing \p ContainerRegion has type +/// \p ContainerType. ElementRegion represents both array elements and casts, +/// so the type of ContainerRegion itself is not sufficient evidence. +static bool hasContainerTypeProvenance(const SubRegion *ContainerRegion, + QualType ContainerType, + ASTContext &Ctx) { + const MemRegion *StorageRegion = ContainerRegion; + if (const auto *ER = dyn_cast<ElementRegion>(ContainerRegion)) { + if (!ASTContext::hasSameUnqualifiedType(ER->getElementType(), + ContainerType)) + return false; + StorageRegion = ER->getSuperRegion(); + } + + QualType StorageType = getRegionObjectType(StorageRegion); + if (StorageType.isNull()) + return false; + + if (const ArrayType *AT = Ctx.getAsArrayType(StorageType)) + StorageType = AT->getElementType(); + + return ASTContext::hasSameUnqualifiedType(StorageType, ContainerType); +} + +/// Return whether the concrete storage containing \p ContainerRegion is large +/// enough to contain an object of \p ContainerType at that region's offset. +/// Return std::nullopt when either the offset or the extent is symbolic. +static std::optional<bool> +hasSufficientContainerExtent(ProgramStateRef State, + const SubRegion *ContainerRegion, + QualType ContainerType, SValBuilder &SVB) { + ASTContext &Ctx = SVB.getContext(); + RegionOffset Offset = ContainerRegion->getAsOffset(); + if (!Offset.isValid() || Offset.hasSymbolicOffset()) + return std::nullopt; + + const int64_t OffsetBits = Offset.getOffset(); + const uint64_t CharWidth = Ctx.getCharWidth(); + if (OffsetBits < 0 || static_cast<uint64_t>(OffsetBits) % CharWidth != 0) + return false; + + const MemRegion *BaseRegion = Offset.getRegion(); + const auto BaseExtent = + getDynamicExtent(State, BaseRegion, SVB).getAs<nonloc::ConcreteInt>(); + if (!BaseExtent) + return std::nullopt; + + const int64_t ContainerSize = + Ctx.getTypeSizeInChars(ContainerType).getQuantity(); + if (ContainerSize < 0) + return false; + + const uint64_t OffsetChars = static_cast<uint64_t>(OffsetBits) / CharWidth; + const uint64_t ContainerSizeChars = static_cast<uint64_t>(ContainerSize); + if (OffsetChars > std::numeric_limits<uint64_t>::max() - ContainerSizeChars) + return false; + + const uint64_t RequiredExtent = OffsetChars + ContainerSizeChars; + const llvm::APSInt RequiredExtentValue = + llvm::APSInt::getUnsigned(RequiredExtent); + return llvm::APSInt::compareValues(*BaseExtent->getValue(), + RequiredExtentValue) >= 0; +} + +const SubRegion *getContainerOfParentRegion(const ElementRegion *ContainerER, + ProgramStateRef State, + SValBuilder &SVB) { + ASTContext &Ctx = SVB.getContext(); + const MemRegion *SuperRegion = ContainerER->getSuperRegion(); + const FieldRegion *FieldR = nullptr; + int64_t CharacterIndex = 0; + + if (const auto *CharacterER = dyn_cast<ElementRegion>(SuperRegion)) { + QualType CharacterType = CharacterER->getElementType(); + if (!CharacterType->isCharType() || + Ctx.getTypeSizeInChars(CharacterType).getQuantity() != 1) ---------------- bozicrHT wrote:
You're right! https://github.com/llvm/llvm-project/pull/214140 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
