ahatanak updated this revision to Diff 61743.
ahatanak added a comment.

Address review comments and change the wording in AttrDocs.td to explain what 
the attribute means and how it is used. Also, fixed the code in VisitMemberExpr 
to set LValue::OverAllocated before the base class of the member expression is 
visited. This change was needed because the base class of the innermost 
MemberExpr has to be examined to see whether the member belongs to an 
overallocated class. Without this change, the last check in 
test/CodeGen/object-size.c fails.


http://reviews.llvm.org/D21453

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  lib/AST/ExprConstant.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/CodeGen/object-size.c
  test/CodeGen/object-size.cpp

Index: test/CodeGen/object-size.cpp
===================================================================
--- test/CodeGen/object-size.cpp
+++ test/CodeGen/object-size.cpp
@@ -62,3 +62,29 @@
   // CHECK: store i32 16
   gi = __builtin_object_size(&c->bs[0].buf[0], 3);
 }
+
+struct S0 {
+  int a[16], b[16];
+} __attribute__((overallocated));
+
+struct S1 : S0 {
+};
+
+struct S2 : S1 {
+} __attribute__((overallocated));
+
+// CHECK-LABEL: define void @_Z5test3v()
+void test3() {
+  struct S0 *s0;
+  struct S1 *s1;
+  struct S2 *s2;
+
+  // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+  gi = __builtin_object_size(s0->b, 1);
+
+  // CHECK: store i32 64, i32* @gi
+  gi = __builtin_object_size(s1->b, 1);
+
+  // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+  gi = __builtin_object_size(s2->b, 1);
+}
Index: test/CodeGen/object-size.c
===================================================================
--- test/CodeGen/object-size.c
+++ test/CodeGen/object-size.c
@@ -517,3 +517,52 @@
   // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
   gi = __builtin_object_size(&dsv[9].snd[0], 1);
 }
+
+union U0 {
+  int a[16], b[16];
+} __attribute__((overallocated));
+
+struct S0 {
+  int a[16], b[16];
+};
+
+struct S1 {
+  int a[16], b[16];
+} __attribute__((overallocated));
+
+struct S2 {
+  int a[16], b[16];
+  struct S1 s1;
+  struct S0 s0;
+} __attribute__((overallocated));
+
+// CHECK-LABEL: @test32
+void test32() {
+  union U0 *u0;
+  struct S1 *s1;
+  struct S2 *s2;
+
+  // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+  gi = __builtin_object_size(u0->a, 1);
+
+  // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+  gi = __builtin_object_size(u0->b, 1);
+
+  // CHECK: store i32 64, i32* @gi
+  gi = __builtin_object_size(s1->a, 1);
+
+  // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+  gi = __builtin_object_size(s1->b, 1);
+
+  // CHECK: store i32 64, i32* @gi
+  gi = __builtin_object_size(s2->b, 1);
+
+  // CHECK: store i32 64, i32* @gi
+  gi = __builtin_object_size(s2->s1.b, 1);
+
+  // CHECK: store i32 128, i32* @gi
+  gi = __builtin_object_size(&s2->s0, 1);
+
+  // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+  gi = __builtin_object_size(s2->s0.b, 1);
+}
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -5394,6 +5394,9 @@
   case AttributeList::AT_X86ForceAlignArgPointer:
     handleX86ForceAlignArgPointerAttr(S, D, Attr);
     break;
+  case AttributeList::AT_OverAllocated:
+    handleSimpleAttribute<OverAllocatedAttr>(S, D, Attr);
+    break;
   case AttributeList::AT_DLLExport:
   case AttributeList::AT_DLLImport:
     handleDLLAttr(S, D, Attr);
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -1049,7 +1049,12 @@
     APValue::LValueBase Base;
     CharUnits Offset;
     bool InvalidBase : 1;
-    unsigned CallIndex : 31;
+
+    // Indicates the enclosing struct is marked overallocated. This is used in
+    // computation of __builtin_object_size.
+    bool OverAllocated : 1;
+
+    unsigned CallIndex : 30;
     SubobjectDesignator Designator;
 
     const APValue::LValueBase getLValueBase() const { return Base; }
@@ -1059,6 +1064,8 @@
     SubobjectDesignator &getLValueDesignator() { return Designator; }
     const SubobjectDesignator &getLValueDesignator() const { return Designator;}
 
+    LValue() : OverAllocated(false) {}
+
     void moveInto(APValue &V) const {
       if (Designator.Invalid)
         V = APValue(Base, Offset, APValue::NoLValuePath(), CallIndex);
@@ -4559,19 +4566,34 @@
 
   bool VisitMemberExpr(const MemberExpr *E) {
     // Handle non-static data members.
+
+    // Check to see if the record is marked overallocated.
+    auto IsOverAllocated = [](QualType RT, const MemberExpr *ME) {
+      const TagDecl *TD = RT->getAsTagDecl();
+
+      if (isa<CXXRecordDecl>(TD))
+        TD = ME->getBase()->getBestDynamicClassType();
+
+      return TD->hasAttr<OverAllocatedAttr>();
+    };
+
     QualType BaseTy;
     bool EvalOK;
     if (E->isArrow()) {
-      EvalOK = EvaluatePointer(E->getBase(), Result, this->Info);
       BaseTy = E->getBase()->getType()->castAs<PointerType>()->getPointeeType();
+      Result.OverAllocated = IsOverAllocated(BaseTy, E);
+      EvalOK = EvaluatePointer(E->getBase(), Result, this->Info);
     } else if (E->getBase()->isRValue()) {
       assert(E->getBase()->getType()->isRecordType());
-      EvalOK = EvaluateTemporary(E->getBase(), Result, this->Info);
       BaseTy = E->getBase()->getType();
+      Result.OverAllocated = IsOverAllocated(BaseTy, E);
+      EvalOK = EvaluateTemporary(E->getBase(), Result, this->Info);
     } else {
-      EvalOK = this->Visit(E->getBase());
       BaseTy = E->getBase()->getType();
+      Result.OverAllocated = IsOverAllocated(BaseTy, E);
+      EvalOK = this->Visit(E->getBase());
     }
+
     if (!EvalOK) {
       if (!this->Info.allowInvalidBaseExpr())
         return false;
@@ -6728,13 +6750,14 @@
   // strcpy(&F->c[0], Bar);
   //
   // So, if we see that we're examining a 1-length (or 0-length) array at the
-  // end of a struct with an unknown base, we give up instead of breaking code
-  // that behaves this way. Note that we only do this when Type=1, because
-  // Type=3 is a lower bound, so answering conservatively is fine.
+  // end of a struct with an unknown base or the last field of a struct marked
+  // overallocated, we give up instead of breaking code that behaves this way.
+  // Note that we only do this when Type=1, because Type=3 is a lower bound, so
+  // answering conservatively is fine.
   if (End.InvalidBase && SubobjectOnly && Type == 1 &&
       End.Designator.Entries.size() == End.Designator.MostDerivedPathLength &&
       End.Designator.MostDerivedIsArrayElement &&
-      End.Designator.MostDerivedArraySize < 2 &&
+      (End.Designator.MostDerivedArraySize < 2 || End.OverAllocated) &&
       isDesignatorAtObjectEnd(Info.Ctx, End))
     return false;
 
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -2067,6 +2067,34 @@
   }];
 }
 
+def OverAllocatedDocs : Documentation {
+  let Category = DocCatType;
+  let Content = [{
+Use ``overallocated`` to indicate a class or union can have extra memory
+allocated at its end. This attribute is primarily used when we want
+__builtin_object_size to return a conservative value for the distance between
+the pointer and the end of the subobject the pointer points to.
+
+For example:
+
+.. code-block:: c++
+
+struct S {
+  char a[4], char b[4];
+} __attribute__((overallocated));
+
+unsigned foo() {
+  void *p = malloc(sizeof(struct S) + 32);
+  void *ptr = ((struct S*)p)->b;
+
+  // Returns 36 instead of 4 because the size of the array subobject ptr points
+  // to is considered to be 36.
+  return __builtin_object_size(((struct S*)p)->b, 1);
+}
+
+  }];
+}
+
 def InternalLinkageDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -2274,6 +2274,12 @@
   let Documentation = [LoopHintDocs, UnrollHintDocs];
 }
 
+def OverAllocated : InheritableAttr {
+  let Spellings = [GNU<"overallocated">, CXX11<"clang", "overallocated">];
+  let Subjects = SubjectList<[Record], ErrorDiag>;
+  let Documentation = [OverAllocatedDocs];
+}
+
 def CapturedRecord : InheritableAttr {
   // This attribute has no spellings as it is only ever created implicitly.
   let Spellings = [];
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to