[clang][dataflow] Add limits to size of modeled data structures in environment.

Adds two new parameters to control the size of data structures modeled in the environment: # of values and depth of data structure.  The environment already prevents creation of recursive data structures, but that was insufficient in practice. Very large structs still ground the analysis to a halt.  These new parameters allow tuning the size more effectively.

In this patch, the parameters are set as internal constants. We leave to a future patch to make these proper model parameters.

Differential Revision: https://reviews.llvm.org/D120510
This commit is contained in:
Yitzhak Mandelbaum 2022-02-24 20:02:00 +00:00
parent 850592ec14
commit 208c25fcbf
2 changed files with 33 additions and 8 deletions

View File

@ -248,7 +248,8 @@ private:
///
/// `Type` must not be null.
Value *createValueUnlessSelfReferential(QualType Type,
llvm::DenseSet<QualType> &Visited);
llvm::DenseSet<QualType> &Visited,
int Depth, int &CreatedValuesCount);
StorageLocation &skip(StorageLocation &Loc, SkipPast SP) const;
const StorageLocation &skip(const StorageLocation &Loc, SkipPast SP) const;

View File

@ -29,6 +29,12 @@
namespace clang {
namespace dataflow {
// FIXME: convert these to parameters of the analysis or environment. Current
// settings have been experimentaly validated, but only for a particular
// analysis.
static constexpr int MaxCompositeValueDepth = 3;
static constexpr int MaxCompositeValueSize = 1000;
/// Returns a map consisting of key-value entries that are present in both maps.
template <typename K, typename V>
llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1,
@ -336,25 +342,40 @@ Value *Environment::getValue(const Expr &E, SkipPast SP) const {
Value *Environment::createValue(QualType Type) {
llvm::DenseSet<QualType> Visited;
return createValueUnlessSelfReferential(Type, Visited);
int CreatedValuesCount = 0;
Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0,
CreatedValuesCount);
if (CreatedValuesCount > MaxCompositeValueSize) {
llvm::errs() << "Attempting to initialize a huge value of type: "
<< Type.getAsString() << "\n";
}
return Val;
}
Value *Environment::createValueUnlessSelfReferential(
QualType Type, llvm::DenseSet<QualType> &Visited) {
QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,
int &CreatedValuesCount) {
assert(!Type.isNull());
// Allow unlimited fields at depth 1; only cap at deeper nesting levels.
if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) ||
Depth > MaxCompositeValueDepth)
return nullptr;
if (Type->isIntegerType()) {
CreatedValuesCount++;
return &takeOwnership(std::make_unique<IntegerValue>());
}
if (Type->isReferenceType()) {
CreatedValuesCount++;
QualType PointeeType = Type->getAs<ReferenceType>()->getPointeeType();
auto &PointeeLoc = createStorageLocation(PointeeType);
if (!Visited.contains(PointeeType.getCanonicalType())) {
Visited.insert(PointeeType.getCanonicalType());
Value *PointeeVal =
createValueUnlessSelfReferential(PointeeType, Visited);
Value *PointeeVal = createValueUnlessSelfReferential(
PointeeType, Visited, Depth, CreatedValuesCount);
Visited.erase(PointeeType.getCanonicalType());
if (PointeeVal != nullptr)
@ -365,13 +386,14 @@ Value *Environment::createValueUnlessSelfReferential(
}
if (Type->isPointerType()) {
CreatedValuesCount++;
QualType PointeeType = Type->getAs<PointerType>()->getPointeeType();
auto &PointeeLoc = createStorageLocation(PointeeType);
if (!Visited.contains(PointeeType.getCanonicalType())) {
Visited.insert(PointeeType.getCanonicalType());
Value *PointeeVal =
createValueUnlessSelfReferential(PointeeType, Visited);
Value *PointeeVal = createValueUnlessSelfReferential(
PointeeType, Visited, Depth, CreatedValuesCount);
Visited.erase(PointeeType.getCanonicalType());
if (PointeeVal != nullptr)
@ -382,6 +404,7 @@ Value *Environment::createValueUnlessSelfReferential(
}
if (Type->isStructureOrClassType()) {
CreatedValuesCount++;
// FIXME: Initialize only fields that are accessed in the context that is
// being analyzed.
llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
@ -394,7 +417,8 @@ Value *Environment::createValueUnlessSelfReferential(
Visited.insert(FieldType.getCanonicalType());
FieldValues.insert(
{Field, createValueUnlessSelfReferential(FieldType, Visited)});
{Field, createValueUnlessSelfReferential(
FieldType, Visited, Depth + 1, CreatedValuesCount)});
Visited.erase(FieldType.getCanonicalType());
}