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

Fix a bug in tryEvaluateBuiltinObjectSize. If the pointer passed to 
__builtin_object_size doesn't point to an array, it should be able to compute 
the exact size of the subobject the pointer points to. Therefore, it should be 
able to tell the last call to __builtin_object_size in 
test/CodeGen/object-size.c should return 128.


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,49 @@
   // 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);
+}
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -4929,6 +4929,12 @@
   }
 }
 
+static void handleOverAllocatedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+  D->addAttr(::new (S.Context)
+             OverAllocatedAttr(Attr.getLoc(), S.Context,
+                               Attr.getAttributeSpellingListIndex()));
+}
+
 static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D,
                                     const AttributeList &Attr) {
   uint32_t NumRegs;
@@ -5394,6 +5400,9 @@
   case AttributeList::AT_X86ForceAlignArgPointer:
     handleX86ForceAlignArgPointerAttr(S, D, Attr);
     break;
+  case AttributeList::AT_OverAllocated:
+    handleOverAllocatedAttr(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);
@@ -4572,6 +4579,15 @@
       EvalOK = this->Visit(E->getBase());
       BaseTy = E->getBase()->getType();
     }
+
+    // Check to see if the parent record is marked overallocated.
+    const TagDecl *TD = BaseTy->getAsTagDecl();
+
+    if (isa<CXXRecordDecl>(TD))
+      TD = E->getBase()->getBestDynamicClassType();
+
+    Result.OverAllocated = TD->hasAttr<OverAllocatedAttr>();
+
     if (!EvalOK) {
       if (!this->Info.allowInvalidBaseExpr())
         return false;
@@ -6728,13 +6744,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,25 @@
   }];
 }
 
+def OverAllocatedDocs : Documentation {
+  let Category = DocCatType;
+  let Content = [{
+Use ``overallocated`` to indicate a struct or union is over-allocated. For example,
+
+.. code-block:: c++
+
+struct S {
+  char a[4], char b[4];
+} __attribute__((overallocated));
+
+unsigned foo() {
+  void *p = malloc(sizeof(struct S) + 32);
+  return __builtin_object_size(((struct S*)p)->b, 1); // Returns 36 instead of 4.
+}
+
+  }];
+}
+
 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, "ExpectedStructOrUnion">;
+  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