]> granicus.if.org Git - clang/commitdiff
For
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 21 Apr 2011 00:27:41 +0000 (00:27 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 21 Apr 2011 00:27:41 +0000 (00:27 +0000)
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

include/clang/AST/Expr.h
lib/AST/Expr.cpp
lib/AST/ExprConstant.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprConstant.cpp
lib/Sema/SemaInit.cpp
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
test/Index/initializer-memory.cpp [new file with mode: 0644]

index 6b616c28b39fff088138618e8c982b63f4974263..74204082264c6cc8cabadf819213aeb7db6787be 100644 (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.
index 1f6c2fab1b8ec3de327cc0497885ad59459489b6..9b978e843958b66ca8671257e0014a729361ca9b 100644 (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())
index 14a1222cad577dc412c07cfabdcbe0692ce0a468..e738f0dc908c75c61c9ddb51644cf36c30a80209 100644 (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;
   }
     
index 6fb9987ecd744bc15b7d91db24eeebe19867c2b1..5b3c0905e54ec457ff116b638098c403b5b4aee6 100644 (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);
       
index 8e26b206ebfb4369c5b28439568c6c733c260e5d..338fb03b8a038957852a397b3de0f3149880c851 100644 (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
index 84ab23e584c1c6642896b5afa576cd61e686f6f4..307db14b58824f70e0a68ae5e69341ad77464406 100644 (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)))
index 79b0e48f139406914d4a445527704c729ef2ca14..19e0e6463b7beba19b33ce68bdba9671724780c7 100644 (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++]);
 }
 
index 6238983f80fe579f89af912829786d7ab4c7cc9c..2a482734154e2dd3cbcbb10fdd9bfb3393d18177 100644 (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;
 }
diff --git a/test/Index/initializer-memory.cpp b/test/Index/initializer-memory.cpp
new file mode 100644 (file)
index 0000000..d0f531f
--- /dev/null
@@ -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)