r356515 - Add a spelling of pass_object_size that uses __builtin_dynamic_object_size

Erik Pilkington via cfe-commits cfe-commits at lists.llvm.org
Tue Mar 19 13:44:18 PDT 2019


Author: epilk
Date: Tue Mar 19 13:44:18 2019
New Revision: 356515

URL: http://llvm.org/viewvc/llvm-project?rev=356515&view=rev
Log:
Add a spelling of pass_object_size that uses __builtin_dynamic_object_size

The attribute pass_dynamic_object_size(n) behaves exactly like
pass_object_size(n), but instead of evaluating __builtin_object_size on calls,
it evaluates __builtin_dynamic_object_size, which has the potential to produce
runtime code when the object size can't be determined statically.

Differential revision: https://reviews.llvm.org/D58757

Modified:
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Basic/AttrDocs.td
    cfe/trunk/lib/AST/ItaniumMangle.cpp
    cfe/trunk/lib/AST/MicrosoftMangle.cpp
    cfe/trunk/lib/CodeGen/CGCall.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/CodeGen/pass-object-size.c
    cfe/trunk/test/CodeGenCXX/mangle-ms.cpp
    cfe/trunk/test/Sema/pass-object-size.c

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=356515&r1=356514&r2=356515&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Tue Mar 19 13:44:18 2019
@@ -1560,7 +1560,9 @@ def ReturnsNonNull : InheritableAttr {
 // pass_object_size(N) indicates that the parameter should have
 // __builtin_object_size with Type=N evaluated on the parameter at the callsite.
 def PassObjectSize : InheritableParamAttr {
-  let Spellings = [Clang<"pass_object_size">];
+  let Spellings = [Clang<"pass_object_size">,
+                   Clang<"pass_dynamic_object_size">];
+  let Accessors = [Accessor<"isDynamic", [Clang<"pass_dynamic_object_size">]>];
   let Args = [IntArgument<"Type">];
   let Subjects = SubjectList<[ParmVar]>;
   let Documentation = [PassObjectSizeDocs];

Modified: cfe/trunk/include/clang/Basic/AttrDocs.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=356515&r1=356514&r2=356515&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/AttrDocs.td (original)
+++ cfe/trunk/include/clang/Basic/AttrDocs.td Tue Mar 19 13:44:18 2019
@@ -698,6 +698,15 @@ Currently, ``pass_object_size`` is a bit
 * It is an error to apply the ``pass_object_size`` attribute to parameters that
   are not pointers. Additionally, any parameter that ``pass_object_size`` is
   applied to must be marked ``const`` at its function's definition.
+
+Clang also supports the ``pass_dynamic_object_size`` attribute, which behaves
+identically to ``pass_object_size``, but evaluates a call to
+``__builtin_dynamic_object_size`` at the callee instead of
+``__builtin_object_size``. ``__builtin_dynamic_object_size`` provides some extra
+runtime checks when the object size can't be determined at compile-time. You can
+read more about ``__builtin_dynamic_object_size`` `here
+<https://clang.llvm.org/docs/LanguageExtensions.html#evaluating-object-size-dynamically>`_.
+
   }];
 }
 

Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=356515&r1=356514&r2=356515&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Tue Mar 19 13:44:18 2019
@@ -2833,7 +2833,10 @@ void CXXNameMangler::mangleBareFunctionT
       if (auto *Attr = FD->getParamDecl(I)->getAttr<PassObjectSizeAttr>()) {
         // Attr can only take 1 character, so we can hardcode the length below.
         assert(Attr->getType() <= 9 && Attr->getType() >= 0);
-        Out << "U17pass_object_size" << Attr->getType();
+        if (Attr->isDynamic())
+          Out << "U25pass_dynamic_object_size" << Attr->getType();
+        else
+          Out << "U17pass_object_size" << Attr->getType();
       }
     }
   }

Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=356515&r1=356514&r2=356515&view=diff
==============================================================================
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Tue Mar 19 13:44:18 2019
@@ -267,7 +267,7 @@ class MicrosoftCXXNameMangler {
   typedef llvm::DenseMap<const void *, unsigned> ArgBackRefMap;
   ArgBackRefMap TypeBackReferences;
 
-  typedef std::set<int> PassObjectSizeArgsSet;
+  typedef std::set<std::pair<int, bool>> PassObjectSizeArgsSet;
   PassObjectSizeArgsSet PassObjectSizeArgs;
 
   ASTContext &getASTContext() const { return Context.getASTContext(); }
@@ -1761,14 +1761,16 @@ void MicrosoftCXXNameMangler::mangleArgu
 void MicrosoftCXXNameMangler::manglePassObjectSizeArg(
     const PassObjectSizeAttr *POSA) {
   int Type = POSA->getType();
+  bool Dynamic = POSA->isDynamic();
 
-  auto Iter = PassObjectSizeArgs.insert(Type).first;
+  auto Iter = PassObjectSizeArgs.insert({Type, Dynamic}).first;
   auto *TypePtr = (const void *)&*Iter;
   ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr);
 
   if (Found == TypeBackReferences.end()) {
-    mangleArtificialTagType(TTK_Enum, "__pass_object_size" + llvm::utostr(Type),
-                           {"__clang"});
+    std::string Name =
+        Dynamic ? "__pass_dynamic_object_size" : "__pass_object_size";
+    mangleArtificialTagType(TTK_Enum, Name + llvm::utostr(Type), {"__clang"});
 
     if (TypeBackReferences.size() < 10) {
       size_t Size = TypeBackReferences.size();

Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=356515&r1=356514&r2=356515&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Tue Mar 19 13:44:18 2019
@@ -3452,7 +3452,7 @@ void CodeGenFunction::EmitCallArgs(
     assert(EmittedArg.getScalarVal() && "We emitted nothing for the arg?");
     llvm::Value *V = evaluateOrEmitBuiltinObjectSize(Arg, PS->getType(), T,
                                                      EmittedArg.getScalarVal(),
-                                                     /*IsDynamic=*/false);
+                                                     PS->isDynamic());
     Args.add(RValue::get(V), SizeTy);
     // If we're emitting args in reverse, be sure to do so with
     // pass_object_size, as well.

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=356515&r1=356514&r2=356515&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Mar 19 13:44:18 2019
@@ -2935,7 +2935,8 @@ static bool hasIdenticalPassObjectSizeAt
     const auto *AttrB = B->getAttr<PassObjectSizeAttr>();
     if (AttrA == AttrB)
       return true;
-    return AttrA && AttrB && AttrA->getType() == AttrB->getType();
+    return AttrA && AttrB && AttrA->getType() == AttrB->getType() &&
+           AttrA->isDynamic() == AttrB->isDynamic();
   };
 
   return std::equal(A->param_begin(), A->param_end(), B->param_begin(), AttrEq);

Modified: cfe/trunk/test/CodeGen/pass-object-size.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/pass-object-size.c?rev=356515&r1=356514&r2=356515&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/pass-object-size.c (original)
+++ cfe/trunk/test/CodeGen/pass-object-size.c Tue Mar 19 13:44:18 2019
@@ -7,6 +7,7 @@ struct Foo {
 };
 
 #define PS(N) __attribute__((pass_object_size(N)))
+#define PDS(N) __attribute__((pass_dynamic_object_size(N)))
 
 int gi = 0;
 
@@ -16,26 +17,52 @@ int ObjectSize0(void *const p PS(0)) {
   return __builtin_object_size(p, 0);
 }
 
+// CHECK-LABEL: define i32 @DynamicObjectSize0(i8* %{{.*}}, i64)
+int DynamicObjectSize0(void *const p PDS(0)) {
+  // CHECK-NOT: @llvm.objectsize
+  return __builtin_dynamic_object_size(p, 0);
+}
+
 // CHECK-LABEL: define i32 @ObjectSize1(i8* %{{.*}}, i64)
 int ObjectSize1(void *const p PS(1)) {
   // CHECK-NOT: @llvm.objectsize
   return __builtin_object_size(p, 1);
 }
 
+// CHECK-LABEL: define i32 @DynamicObjectSize1(i8* %{{.*}}, i64)
+int DynamicObjectSize1(void *const p PDS(1)) {
+  // CHECK-NOT: @llvm.objectsize
+  return __builtin_dynamic_object_size(p, 1);
+}
+
 // CHECK-LABEL: define i32 @ObjectSize2(i8* %{{.*}}, i64)
 int ObjectSize2(void *const p PS(2)) {
   // CHECK-NOT: @llvm.objectsize
   return __builtin_object_size(p, 2);
 }
 
+// CHECK-LABEL: define i32 @DynamicObjectSize2(i8* %{{.*}}, i64)
+int DynamicObjectSize2(void *const p PDS(2)) {
+  // CHECK-NOT: @llvm.objectsize
+  return __builtin_object_size(p, 2);
+}
+
 // CHECK-LABEL: define i32 @ObjectSize3(i8* %{{.*}}, i64)
 int ObjectSize3(void *const p PS(3)) {
   // CHECK-NOT: @llvm.objectsize
   return __builtin_object_size(p, 3);
 }
 
+// CHECK-LABEL: define i32 @DynamicObjectSize3(i8* %{{.*}}, i64)
+int DynamicObjectSize3(void *const p PDS(3)) {
+  // CHECK-NOT: @llvm.objectsize
+  return __builtin_object_size(p, 3);
+}
+
+void *malloc(unsigned long) __attribute__((alloc_size(1)));
+
 // CHECK-LABEL: define void @test1
-void test1() {
+void test1(unsigned long sz) {
   struct Foo t[10];
 
   // CHECK: call i32 @ObjectSize0(i8* %{{.*}}, i64 360)
@@ -55,6 +82,21 @@ void test1() {
   gi = ObjectSize2(&t[1].t[1]);
   // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 36)
   gi = ObjectSize3(&t[1].t[1]);
+
+  char *ptr = (char *)malloc(sz);
+
+  // CHECK: [[REG:%.*]] = call i64 @llvm.objectsize.i64.p0i8({{.*}}, i1 false, i1 true, i1 true)
+  // CHECK: call i32 @DynamicObjectSize0(i8* %{{.*}}, i64 [[REG]])
+  gi = DynamicObjectSize0(ptr);
+
+  // CHECK: [[WITH_OFFSET:%.*]] = getelementptr
+  // CHECK: [[REG:%.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* [[WITH_OFFSET]], i1 false, i1 true, i1 true)
+  // CHECK: call i32 @DynamicObjectSize0(i8* {{.*}}, i64 [[REG]])
+  gi = DynamicObjectSize0(ptr+10);
+
+  // CHECK: [[REG:%.*]] = call i64 @llvm.objectsize.i64.p0i8({{.*}}, i1 true, i1 true, i1 true)
+  // CHECK: call i32 @DynamicObjectSize2(i8* {{.*}}, i64 [[REG]])
+  gi = DynamicObjectSize2(ptr);
 }
 
 // CHECK-LABEL: define void @test2
@@ -72,6 +114,13 @@ int NoViableOverloadObjectSize0(void *co
   return __builtin_object_size(p, 0);
 }
 
+// CHECK-LABEL: define i32 @_Z34NoViableOverloadDynamicObjectSize0Pv
+int NoViableOverloadDynamicObjectSize0(void *const p)
+  __attribute__((overloadable)) {
+  // CHECK: @llvm.objectsize
+  return __builtin_object_size(p, 0);
+}
+
 // CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize1Pv
 int NoViableOverloadObjectSize1(void *const p) __attribute__((overloadable)) {
   // CHECK: @llvm.objectsize
@@ -97,6 +146,11 @@ int NoViableOverloadObjectSize0(void *co
   return __builtin_object_size(p, 0);
 }
 
+int NoViableOverloadDynamicObjectSize0(void *const p PDS(0))
+  __attribute__((overloadable)) {
+  return __builtin_dynamic_object_size(p, 0);
+}
+
 int NoViableOverloadObjectSize1(void *const p PS(1))
     __attribute__((overloadable)) {
   return __builtin_object_size(p, 1);
@@ -154,6 +208,9 @@ void test3() {
   gi = NoViableOverloadObjectSize2(&t[1].t[1]);
   // CHECK: call i32 @_Z27NoViableOverloadObjectSize3PvU17pass_object_size3(i8* %{{.*}}, i64 36)
   gi = NoViableOverloadObjectSize3(&t[1].t[1]);
+
+  // CHECK: call i32 @_Z34NoViableOverloadDynamicObjectSize0PvU25pass_dynamic_object_size0(i8* %{{.*}}, i64 360)
+  gi = NoViableOverloadDynamicObjectSize0(&t[1]);
 }
 
 // CHECK-LABEL: define void @test4
@@ -183,6 +240,9 @@ void test5() {
 
   int (*f)(void *) = &NoViableOverloadObjectSize0;
   gi = f(&t[1]);
+
+  int (*g)(void *) = &NoViableOverloadDynamicObjectSize0;
+  gi = g(&t[1]);
 }
 
 // CHECK-LABEL: define i32 @IndirectObjectSize0
@@ -213,6 +273,12 @@ int IndirectObjectSize3(void *const p PS
   return ObjectSize3(p);
 }
 
+int IndirectDynamicObjectSize0(void *const p PDS(0)) {
+  // CHECK: call i32 @ObjectSize0(i8* %{{.*}}, i64 %{{.*}})
+  // CHECK-NOT: @llvm.objectsize
+  return ObjectSize0(p);
+}
+
 int Overload0(void *, size_t, void *, size_t);
 int OverloadNoSize(void *, void *);
 
@@ -418,3 +484,10 @@ void test17(char *C) {
   // CHECK: call i32 @ObjectSize0(i8* [[PTR]]
   ObjectSize0(C + ({ int a = 65535; a; }));
 }
+
+// CHECK-LABEL: define void @test18
+void test18(char *const p PDS(0)) {
+  // CHECK-NOT: llvm.objectsize
+  gi = __builtin_dynamic_object_size(p, 0);
+  gi = __builtin_object_size(p, 0);
+}

Modified: cfe/trunk/test/CodeGenCXX/mangle-ms.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-ms.cpp?rev=356515&r1=356514&r2=356515&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/mangle-ms.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/mangle-ms.cpp Tue Mar 19 13:44:18 2019
@@ -457,6 +457,8 @@ int bar(int *const i __attribute__((pass
 int qux(int *const i __attribute__((pass_object_size(1))), int *const j __attribute__((pass_object_size(0)))) { return 0; }
 // CHECK-DAG: define dso_local i32 @"?zot at PassObjectSize@@YAHQAHW4__pass_object_size1 at __clang@@01 at Z"
 int zot(int *const i __attribute__((pass_object_size(1))), int *const j __attribute__((pass_object_size(1)))) { return 0; }
+// CHECK-DAG: define dso_local i32 @"?silly_word at PassObjectSize@@YAHQAHW4__pass_dynamic_object_size1 at __clang@@@Z"
+int silly_word(int *const i __attribute__((pass_dynamic_object_size(1)))) { return 0; }
 }
 
 namespace Atomic {

Modified: cfe/trunk/test/Sema/pass-object-size.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/pass-object-size.c?rev=356515&r1=356514&r2=356515&view=diff
==============================================================================
--- cfe/trunk/test/Sema/pass-object-size.c (original)
+++ cfe/trunk/test/Sema/pass-object-size.c Tue Mar 19 13:44:18 2019
@@ -17,6 +17,9 @@ void h(char *p __attribute__((pass_objec
 void i(char *p __attribute__((pass_object_size(0)))); // OK -- const is only necessary on definitions, not decls.
 void j(char *p __attribute__((pass_object_size(0), pass_object_size(1)))); //expected-error{{'pass_object_size' attribute can only be applied once per parameter}}
 
+void k(char *p __attribute__((pass_dynamic_object_size))); // expected-error {{'pass_dynamic_object_size' attribute takes one argument}}
+void l(int p __attribute__((pass_dynamic_object_size(0)))); // expected-error {{'pass_dynamic_object_size' attribute only applies to constant pointer arguments}}
+
 #define PS(N) __attribute__((pass_object_size(N)))
 #define overloaded __attribute__((overloadable))
 void Overloaded(void *p PS(0)) overloaded; //expected-note{{previous declaration is here}}
@@ -32,14 +35,17 @@ void TakeFnOvl(void (*)(void *)) overloa
 void TakeFnOvl(void (*)(int *)) overloaded;
 
 void NotOverloaded(void *p PS(0));
-void IsOverloaded(void *p PS(0)) overloaded;
-void IsOverloaded(char *p) overloaded; // char* inestead of void* is intentional
+void IsOverloaded(void *p PS(0)) overloaded; // expected-note 2 {{candidate address cannot be taken because parameter 1 has pass_object_size attribute}}
+
+// char* inestead of void* is intentional
+void IsOverloaded(char *p) overloaded; // expected-note{{passing argument to parameter 'p' here}} expected-note 2 {{type mismatch}}
+
 void FunctionPtrs() {
   void (*p)(void *) = NotOverloaded; //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
   void (*p2)(void *) = &NotOverloaded; //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
 
-  void (*p3)(void *) = IsOverloaded; //expected-warning{{incompatible pointer types initializing 'void (*)(void *)' with an expression of type '<overloaded function type>'}} expected-note at -6{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note at -5{{type mismatch}}
-  void (*p4)(void *) = &IsOverloaded; //expected-warning{{incompatible pointer types initializing 'void (*)(void *)' with an expression of type '<overloaded function type>'}} expected-note at -7{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note at -6{{type mismatch}}
+  void (*p3)(void *) = IsOverloaded; //expected-warning{{incompatible pointer types initializing 'void (*)(void *)' with an expression of type '<overloaded function type>'}}
+  void (*p4)(void *) = &IsOverloaded; //expected-warning{{incompatible pointer types initializing 'void (*)(void *)' with an expression of type '<overloaded function type>'}}
 
   void (*p5)(char *) = IsOverloaded;
   void (*p6)(char *) = &IsOverloaded;
@@ -52,5 +58,11 @@ void FunctionPtrs() {
 
   int P;
   (&NotOverloaded)(&P); //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
-  (&IsOverloaded)(&P); //expected-warning{{incompatible pointer types passing 'int *' to parameter of type 'char *'}} expected-note at 36{{passing argument to parameter 'p' here}}
+  (&IsOverloaded)(&P); //expected-warning{{incompatible pointer types passing 'int *' to parameter of type 'char *'}}
 }
+
+void mismatch(void *p __attribute__((pass_object_size(0)))); // expected-note {{previous declaration is here}}
+void mismatch(void *p __attribute__((pass_dynamic_object_size(0)))); // expected-error {{conflicting pass_object_size attributes on parameters}}
+
+void mismatch2(void *p __attribute__((pass_dynamic_object_size(0)))); // expected-note {{previous declaration is here}}
+void mismatch2(void *p __attribute__((pass_dynamic_object_size(1)))); // expected-error {{conflicting pass_object_size attributes on parameters}}




More information about the cfe-commits mailing list