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.

llvm-svn: 129896
This commit is contained in:
Argyrios Kyrtzidis 2011-04-21 00:27:41 +00:00
parent 21b2b7db76
commit b2ed28ea4b
9 changed files with 82 additions and 17 deletions

View File

@ -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.

View File

@ -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())

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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)))

View File

@ -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++]);
}

View File

@ -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;
}

View File

@ -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)