double data[20000000] = {0};

we would blow out the memory by creating 20M Exprs to fill out the initializer.

To fix this, if the initializer list initializes an array with more elements than
there are initializers in the list, have InitListExpr store a single 'ArrayFiller' expression
that specifies an expression to be used for value initialization of the rest of the elements.

Fixes rdar://9275920.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129896 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Argyrios Kyrtzidis 2011-04-21 00:27:41 +00:00
Родитель e0047b13f0
Коммит 4423ac0282
9 изменённых файлов: 82 добавлений и 17 удалений

Просмотреть файл

@ -3178,9 +3178,14 @@ class InitListExpr : public Expr {
/// written in the source code.
InitListExpr *SyntacticForm;
/// If this initializer list initializes a union, specifies which
/// field within the union will be initialized.
FieldDecl *UnionFieldInit;
/// \brief Either:
/// If this initializer list initializes an array with more elements than
/// there are initializers in the list, specifies an expression to be used
/// for value initialization of the rest of the elements.
/// Or
/// If this initializer list initializes a union, specifies which
/// field within the union will be initialized.
llvm::PointerUnion<Expr *, FieldDecl *> ArrayFillerOrUnionFieldInit;
/// Whether this initializer list originally had a GNU array-range
/// designator in it. This is a temporary marker used by CodeGen.
@ -3235,14 +3240,28 @@ public:
/// accommodate the new entry.
Expr *updateInit(ASTContext &C, unsigned Init, Expr *expr);
/// \brief If this initializer list initializes an array with more elements
/// than there are initializers in the list, specifies an expression to be
/// used for value initialization of the rest of the elements.
Expr *getArrayFiller() {
return ArrayFillerOrUnionFieldInit.dyn_cast<Expr *>();
}
void setArrayFiller(Expr *filler) {
ArrayFillerOrUnionFieldInit = filler;
}
/// \brief If this initializes a union, specifies which field in the
/// union to initialize.
///
/// Typically, this field is the first named field within the
/// union. However, a designated initializer can specify the
/// initialization of a different field within the union.
FieldDecl *getInitializedFieldInUnion() { return UnionFieldInit; }
void setInitializedFieldInUnion(FieldDecl *FD) { UnionFieldInit = FD; }
FieldDecl *getInitializedFieldInUnion() {
return ArrayFillerOrUnionFieldInit.dyn_cast<FieldDecl *>();
}
void setInitializedFieldInUnion(FieldDecl *FD) {
ArrayFillerOrUnionFieldInit = FD;
}
// Explicit InitListExpr's originate from source code (and have valid source
// locations). Implicit InitListExpr's are created by the semantic analyzer.
@ -3293,6 +3312,9 @@ public:
const_reverse_iterator rbegin() const { return InitExprs.rbegin(); }
reverse_iterator rend() { return InitExprs.rend(); }
const_reverse_iterator rend() const { return InitExprs.rend(); }
friend class ASTStmtReader;
friend class ASTStmtWriter;
};
/// @brief Represents a C99 designated initializer expression.

Просмотреть файл

@ -1254,7 +1254,7 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
false),
InitExprs(C, numInits),
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0),
UnionFieldInit(0), HadArrayRangeDesignator(false)
HadArrayRangeDesignator(false)
{
for (unsigned I = 0; I != numInits; ++I) {
if (initExprs[I]->isTypeDependent())

Просмотреть файл

@ -319,6 +319,8 @@ public:
bool VisitInitListExpr(InitListExpr *E) {
for (unsigned i = 0, e = E->getNumInits(); i != e; ++i)
if (Visit(E->getInit(i))) return true;
if (Expr *filler = E->getArrayFiller())
return Visit(filler);
return false;
}

Просмотреть файл

@ -641,6 +641,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (i < NumInitElements)
EmitInitializationToLValue(E->getInit(i), LV, ElementType);
else if (Expr *filler = E->getArrayFiller())
EmitInitializationToLValue(filler, LV, ElementType);
else
EmitNullInitializationToLValue(LV, ElementType);

Просмотреть файл

@ -667,8 +667,16 @@ public:
// Initialize remaining array elements.
// FIXME: This doesn't handle member pointers correctly!
llvm::Constant *fillC;
if (Expr *filler = ILE->getArrayFiller())
fillC = CGM.EmitConstantExpr(filler, filler->getType(), CGF);
else
fillC = llvm::Constant::getNullValue(ElemTy);
if (!fillC)
return 0;
RewriteType |= (fillC->getType() != ElemTy);
for (; i < NumElements; ++i)
Elts.push_back(llvm::Constant::getNullValue(ElemTy));
Elts.push_back(fillC);
if (RewriteType) {
// FIXME: Try to avoid packing the array

Просмотреть файл

@ -405,14 +405,23 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
// Do nothing
} else if (Init < NumInits) {
ILE->setInit(Init, ElementInit.takeAs<Expr>());
} else if (InitSeq.getKind()
} else {
// For arrays, just set the expression used for value-initialization
// of the rest of elements and exit.
if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement) {
ILE->setArrayFiller(ElementInit.takeAs<Expr>());
return;
}
if (InitSeq.getKind()
== InitializationSequence::ConstructorInitialization) {
// Value-initialization requires a constructor call, so
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
// through the initializer list.
ILE->updateInit(SemaRef.Context, Init, ElementInit.takeAs<Expr>());
RequiresSecondPass = true;
// Value-initialization requires a constructor call, so
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
// through the initializer list.
ILE->updateInit(SemaRef.Context, Init, ElementInit.takeAs<Expr>());
RequiresSecondPass = true;
}
}
} else if (InitListExpr *InnerILE
= dyn_cast<InitListExpr>(ILE->getInit(Init)))

Просмотреть файл

@ -690,8 +690,11 @@ void ASTStmtReader::VisitInitListExpr(InitListExpr *E) {
E->setSyntacticForm(cast_or_null<InitListExpr>(Reader.ReadSubStmt()));
E->setLBraceLoc(ReadSourceLocation(Record, Idx));
E->setRBraceLoc(ReadSourceLocation(Record, Idx));
E->setInitializedFieldInUnion(
cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])));
if (Record[Idx++]) // isArrayFiller
E->ArrayFillerOrUnionFieldInit = Reader.ReadSubExpr();
else
E->ArrayFillerOrUnionFieldInit
= cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++]));
E->sawArrayRangeDesignator(Record[Idx++]);
}

Просмотреть файл

@ -673,7 +673,12 @@ void ASTStmtWriter::VisitInitListExpr(InitListExpr *E) {
Writer.AddStmt(E->getSyntacticForm());
Writer.AddSourceLocation(E->getLBraceLoc(), Record);
Writer.AddSourceLocation(E->getRBraceLoc(), Record);
Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record);
bool isArrayFiller = E->ArrayFillerOrUnionFieldInit.is<Expr*>();
Record.push_back(isArrayFiller);
if (isArrayFiller)
Writer.AddStmt(E->getArrayFiller());
else
Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record);
Record.push_back(E->hadArrayRangeDesignator());
Code = serialization::EXPR_INIT_LIST;
}

Просмотреть файл

@ -0,0 +1,14 @@
// RUN: c-index-test -test-load-source-memory-usage none %s 2>&1 | FileCheck %s
// rdar://9275920 - We would create millions of Exprs to fill out the initializer.
double data[1000000] = {0};
struct S {
S(int);
S();
};
S data2[1000000] = {0};
// CHECK: TOTAL = {{.*}} (0.{{.*}} MBytes)