[clang] dc4abca - Handle alloc_size attribute on function pointers

Alex Richardson via cfe-commits cfe-commits at lists.llvm.org
Fri Apr 9 10:50:38 PDT 2021


Author: Alex Richardson
Date: 2021-04-09T18:49:38+01:00
New Revision: dc4abca7662b74467c2b6bceb7e8b046ae04b8a0

URL: https://github.com/llvm/llvm-project/commit/dc4abca7662b74467c2b6bceb7e8b046ae04b8a0
DIFF: https://github.com/llvm/llvm-project/commit/dc4abca7662b74467c2b6bceb7e8b046ae04b8a0.diff

LOG: Handle alloc_size attribute on function pointers

I have been trying to statically find and analyze all calls to heap
allocation functions to determine how many of them use sizes known at
compile time vs only at runtime. While doing so I saw that quite a few
projects use replaceable function pointers for heap allocation and noticed
that clang was not able to annotate functions pointers with alloc_size.
I have changed the Sema checks to allow alloc_size on all function pointers
and typedefs for function pointers now and added checks that these
attributes are propagated to the LLVM IR correctly.

With this patch we can also compute __builtin_object_size() for calls to
allocation function pointers with the alloc_size attribute.

Reviewed By: aaron.ballman, erik.pilkington
Differential Revision: https://reviews.llvm.org/D55212

Added: 
    clang/test/CodeGen/alloc-size-fnptr.c

Modified: 
    clang/include/clang/Basic/Attr.td
    clang/lib/AST/ExprConstant.cpp
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaDeclAttr.cpp
    clang/test/CodeGen/alloc-size.c
    clang/test/Misc/pragma-attribute-supported-attributes-list.test
    clang/test/Sema/alloc-size.c

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index d9c2422536d0c..400dfe84b7d98 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1308,7 +1308,7 @@ def EmptyBases : InheritableAttr, TargetSpecificAttr<TargetMicrosoftCXXABI> {
 
 def AllocSize : InheritableAttr {
   let Spellings = [GCC<"alloc_size">];
-  let Subjects = SubjectList<[Function]>;
+  let Subjects = SubjectList<[HasFunctionProto]>;
   let Args = [ParamIdxArgument<"ElemSizeParam">,
               ParamIdxArgument<"NumElemsParam", /*opt*/ 1>];
   let TemplateDependent = 1;

diff  --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index fe6573b8bd2c1..5a68b1c3cad17 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -108,8 +108,11 @@ namespace {
 
   /// Given a CallExpr, try to get the alloc_size attribute. May return null.
   static const AllocSizeAttr *getAllocSizeAttr(const CallExpr *CE) {
-    const FunctionDecl *Callee = CE->getDirectCallee();
-    return Callee ? Callee->getAttr<AllocSizeAttr>() : nullptr;
+    if (const FunctionDecl *DirectCallee = CE->getDirectCallee())
+      return DirectCallee->getAttr<AllocSizeAttr>();
+    if (const Decl *IndirectCallee = CE->getCalleeDecl())
+      return IndirectCallee->getAttr<AllocSizeAttr>();
+    return nullptr;
   }
 
   /// Attempts to unwrap a CallExpr (with an alloc_size attribute) from an Expr.

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index dbc217640fd56..17d63bf1f1364 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -6831,6 +6831,16 @@ static bool diagnoseOpenCLTypes(Scope *S, Sema &Se, Declarator &D,
   return true;
 }
 
+template <typename AttrTy>
+static void copyAttrFromTypedefToDecl(Sema &S, Decl *D, const TypedefType *TT) {
+  const TypedefNameDecl *TND = TT->getDecl();
+  if (const auto *Attribute = TND->getAttr<AttrTy>()) {
+    AttrTy *Clone = Attribute->clone(S.Context);
+    Clone->setInherited(true);
+    D->addAttr(Clone);
+  }
+}
+
 NamedDecl *Sema::ActOnVariableDeclarator(
     Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo,
     LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists,
@@ -7253,6 +7263,14 @@ NamedDecl *Sema::ActOnVariableDeclarator(
   // Handle attributes prior to checking for duplicates in MergeVarDecl
   ProcessDeclAttributes(S, NewVD, D);
 
+  // FIXME: This is probably the wrong location to be doing this and we should
+  // probably be doing this for more attributes (especially for function
+  // pointer attributes such as format, warn_unused_result, etc.). Ideally
+  // the code to copy attributes would be generated by TableGen.
+  if (R->isFunctionPointerType())
+    if (const auto *TT = R->getAs<TypedefType>())
+      copyAttrFromTypedefToDecl<AllocSizeAttr>(*this, NewVD, TT);
+
   if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice ||
       getLangOpts().SYCLIsDevice) {
     if (EmitTLSUnsupportedError &&

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 550fa503bf569..43ca644ed21ed 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -788,20 +788,20 @@ static void handleAssertExclusiveLockAttr(Sema &S, Decl *D,
 ///
 /// AttrArgNo is used to actually retrieve the argument, so it's base-0.
 template <typename AttrInfo>
-static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD,
-                                    const AttrInfo &AI, unsigned AttrArgNo) {
+static bool checkParamIsIntegerType(Sema &S, const Decl *D, const AttrInfo &AI,
+                                    unsigned AttrArgNo) {
   assert(AI.isArgExpr(AttrArgNo) && "Expected expression argument");
   Expr *AttrArg = AI.getArgAsExpr(AttrArgNo);
   ParamIdx Idx;
-  if (!checkFunctionOrMethodParameterIndex(S, FD, AI, AttrArgNo + 1, AttrArg,
+  if (!checkFunctionOrMethodParameterIndex(S, D, AI, AttrArgNo + 1, AttrArg,
                                            Idx))
     return false;
 
-  const ParmVarDecl *Param = FD->getParamDecl(Idx.getASTIndex());
-  if (!Param->getType()->isIntegerType() && !Param->getType()->isCharType()) {
+  QualType ParamTy = getFunctionOrMethodParamType(D, Idx.getASTIndex());
+  if (!ParamTy->isIntegerType() && !ParamTy->isCharType()) {
     SourceLocation SrcLoc = AttrArg->getBeginLoc();
     S.Diag(SrcLoc, diag::err_attribute_integers_only)
-        << AI << Param->getSourceRange();
+        << AI << getFunctionOrMethodParamRange(D, Idx.getASTIndex());
     return false;
   }
   return true;
@@ -811,8 +811,10 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 2))
     return;
 
-  const auto *FD = cast<FunctionDecl>(D);
-  if (!FD->getReturnType()->isPointerType()) {
+  assert(isFunctionOrMethod(D) && hasFunctionProto(D));
+
+  QualType RetTy = getFunctionOrMethodResultType(D);
+  if (!RetTy->isPointerType()) {
     S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) << AL;
     return;
   }
@@ -822,7 +824,7 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   // Parameter indices are 1-indexed, hence Index=1
   if (!checkPositiveIntArgument(S, AL, SizeExpr, SizeArgNoVal, /*Idx=*/1))
     return;
-  if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/0))
+  if (!checkParamIsIntegerType(S, D, AL, /*AttrArgNo=*/0))
     return;
   ParamIdx SizeArgNo(SizeArgNoVal, D);
 
@@ -833,7 +835,7 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
     // Parameter indices are 1-based, hence Index=2
     if (!checkPositiveIntArgument(S, AL, NumberExpr, Val, /*Idx=*/2))
       return;
-    if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/1))
+    if (!checkParamIsIntegerType(S, D, AL, /*AttrArgNo=*/1))
       return;
     NumberArgNo = ParamIdx(Val, D);
   }

diff  --git a/clang/test/CodeGen/alloc-size-fnptr.c b/clang/test/CodeGen/alloc-size-fnptr.c
new file mode 100644
index 0000000000000..ff410c053f9f5
--- /dev/null
+++ b/clang/test/CodeGen/alloc-size-fnptr.c
@@ -0,0 +1,55 @@
+// Check that the alloc_size attribute is propagated to the call instruction
+// for both direct and indirect calls
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm %s -o - 2>&1 | FileCheck %s
+
+#define NULL ((void *)0)
+
+int gi;
+
+typedef unsigned long size_t;
+
+extern void *my_malloc(int) __attribute__((alloc_size(1)));
+extern void *my_calloc(int, int) __attribute__((alloc_size(1, 2)));
+
+// CHECK-LABEL: @call_direct
+void call_direct(void) {
+  my_malloc(50);
+  // CHECK: call i8* @my_malloc(i32 50) [[DIRECT_MALLOC_ATTR:#[0-9]+]]
+  my_calloc(1, 16);
+  // CHECK: call i8* @my_calloc(i32 1, i32 16) [[DIRECT_CALLOC_ATTR:#[0-9]+]]
+}
+
+extern void *(*malloc_function_pointer)(void *, int)__attribute__((alloc_size(2)));
+extern void *(*calloc_function_pointer)(void *, int, int)__attribute__((alloc_size(2, 3)));
+
+// CHECK-LABEL: @call_function_pointer
+void call_function_pointer(void) {
+  malloc_function_pointer(NULL, 100);
+  // CHECK: [[MALLOC_FN_PTR:%.+]] = load i8* (i8*, i32)*, i8* (i8*, i32)** @malloc_function_pointer, align 8
+  // CHECK: call i8* [[MALLOC_FN_PTR]](i8* null, i32 100) [[INDIRECT_MALLOC_ATTR:#[0-9]+]]
+  calloc_function_pointer(NULL, 2, 4);
+  // CHECK: [[CALLOC_FN_PTR:%.+]] = load i8* (i8*, i32, i32)*, i8* (i8*, i32, i32)** @calloc_function_pointer, align 8
+  // CHECK: call i8* [[CALLOC_FN_PTR]](i8* null, i32 2, i32 4) [[INDIRECT_CALLOC_ATTR:#[0-9]+]]
+}
+
+typedef void *(__attribute__((alloc_size(3))) * my_malloc_fn_pointer_type)(void *, void *, int);
+typedef void *(__attribute__((alloc_size(3, 4))) * my_calloc_fn_pointer_type)(void *, void *, int, int);
+extern my_malloc_fn_pointer_type malloc_function_pointer_with_typedef;
+extern my_calloc_fn_pointer_type calloc_function_pointer_with_typedef;
+
+// CHECK-LABEL: @call_function_pointer_typedef
+void call_function_pointer_typedef(void) {
+  malloc_function_pointer_with_typedef(NULL, NULL, 200);
+  // CHECK: [[INDIRECT_TYPEDEF_MALLOC_FN_PTR:%.+]] = load i8* (i8*, i8*, i32)*, i8* (i8*, i8*, i32)** @malloc_function_pointer_with_typedef, align 8
+  // CHECK: call i8* [[INDIRECT_TYPEDEF_MALLOC_FN_PTR]](i8* null, i8* null, i32 200) [[INDIRECT_TYPEDEF_MALLOC_ATTR:#[0-9]+]]
+  calloc_function_pointer_with_typedef(NULL, NULL, 8, 4);
+  // CHECK: [[INDIRECT_TYPEDEF_CALLOC_FN_PTR:%.+]] = load i8* (i8*, i8*, i32, i32)*, i8* (i8*, i8*, i32, i32)** @calloc_function_pointer_with_typedef, align 8
+  // CHECK: call i8* [[INDIRECT_TYPEDEF_CALLOC_FN_PTR]](i8* null, i8* null, i32 8, i32 4) [[INDIRECT_TYPEDEF_CALLOC_ATTR:#[0-9]+]]
+}
+
+// CHECK: attributes [[DIRECT_MALLOC_ATTR]] = { allocsize(0) }
+// CHECK: attributes [[DIRECT_CALLOC_ATTR]] = { allocsize(0,1) }
+// CHECK: attributes [[INDIRECT_MALLOC_ATTR]] = { allocsize(1) }
+// CHECK: attributes [[INDIRECT_CALLOC_ATTR]] = { allocsize(1,2) }
+// CHECK: attributes [[INDIRECT_TYPEDEF_MALLOC_ATTR]] = { allocsize(2) }
+// CHECK: attributes [[INDIRECT_TYPEDEF_CALLOC_ATTR]] = { allocsize(2,3) }

diff  --git a/clang/test/CodeGen/alloc-size.c b/clang/test/CodeGen/alloc-size.c
index 16cc0fe11816f..242fa41cd2c08 100644
--- a/clang/test/CodeGen/alloc-size.c
+++ b/clang/test/CodeGen/alloc-size.c
@@ -366,3 +366,128 @@ void test13() {
   // CHECK: store i32 128,
   gi = OBJECT_SIZE_BUILTIN(alloc_uchar(128), 0);
 }
+
+void *(*malloc_function_pointer)(int)__attribute__((alloc_size(1)));
+void *(*calloc_function_pointer)(int, int)__attribute__((alloc_size(1, 2)));
+
+// CHECK-LABEL: @test_fn_pointer
+void test_fn_pointer() {
+  void *const vp = malloc_function_pointer(100);
+  // CHECK: store i32 100
+  gi = __builtin_object_size(vp, 0);
+  // CHECK: store i32 100
+  gi = __builtin_object_size(vp, 1);
+  // CHECK: store i32 100
+  gi = __builtin_object_size(vp, 2);
+  // CHECK: store i32 100
+  gi = __builtin_object_size(vp, 3);
+
+  void *const arr = calloc_function_pointer(100, 5);
+  // CHECK: store i32 500
+  gi = __builtin_object_size(arr, 0);
+  // CHECK: store i32 500
+  gi = __builtin_object_size(arr, 1);
+  // CHECK: store i32 500
+  gi = __builtin_object_size(arr, 2);
+  // CHECK: store i32 500
+  gi = __builtin_object_size(arr, 3);
+
+  // CHECK: store i32 100
+  gi = __builtin_object_size(malloc_function_pointer(100), 0);
+  // CHECK: store i32 100
+  gi = __builtin_object_size(malloc_function_pointer(100), 1);
+  // CHECK: store i32 100
+  gi = __builtin_object_size(malloc_function_pointer(100), 2);
+  // CHECK: store i32 100
+  gi = __builtin_object_size(malloc_function_pointer(100), 3);
+
+  // CHECK: store i32 500
+  gi = __builtin_object_size(calloc_function_pointer(100, 5), 0);
+  // CHECK: store i32 500
+  gi = __builtin_object_size(calloc_function_pointer(100, 5), 1);
+  // CHECK: store i32 500
+  gi = __builtin_object_size(calloc_function_pointer(100, 5), 2);
+  // CHECK: store i32 500
+  gi = __builtin_object_size(calloc_function_pointer(100, 5), 3);
+
+  void *const zeroPtr = malloc_function_pointer(0);
+  // CHECK: store i32 0
+  gi = __builtin_object_size(zeroPtr, 0);
+  // CHECK: store i32 0
+  gi = __builtin_object_size(malloc_function_pointer(0), 0);
+
+  void *const zeroArr1 = calloc_function_pointer(0, 1);
+  void *const zeroArr2 = calloc_function_pointer(1, 0);
+  // CHECK: store i32 0
+  gi = __builtin_object_size(zeroArr1, 0);
+  // CHECK: store i32 0
+  gi = __builtin_object_size(zeroArr2, 0);
+  // CHECK: store i32 0
+  gi = __builtin_object_size(calloc_function_pointer(1, 0), 0);
+  // CHECK: store i32 0
+  gi = __builtin_object_size(calloc_function_pointer(0, 1), 0);
+}
+
+typedef void *(__attribute__((warn_unused_result, alloc_size(1))) * my_malloc_function_pointer_type)(int);
+typedef void *(__attribute__((alloc_size(1, 2))) * my_calloc_function_pointer_type)(int, int);
+extern my_malloc_function_pointer_type malloc_function_pointer_with_typedef;
+extern my_calloc_function_pointer_type calloc_function_pointer_with_typedef;
+
+// CHECK-LABEL: @test_fn_pointer_typedef
+void test_fn_pointer_typedef() {
+  malloc_function_pointer_with_typedef(100);
+  void *const vp = malloc_function_pointer_with_typedef(100);
+  // CHECK: store i32 100
+  gi = __builtin_object_size(vp, 0);
+  // CHECK: store i32 100
+  gi = __builtin_object_size(vp, 1);
+  // CHECK: store i32 100
+  gi = __builtin_object_size(vp, 2);
+  // CHECK: store i32 100
+  gi = __builtin_object_size(vp, 3);
+
+  void *const arr = calloc_function_pointer_with_typedef(100, 5);
+  // CHECK: store i32 500
+  gi = __builtin_object_size(arr, 0);
+  // CHECK: store i32 500
+  gi = __builtin_object_size(arr, 1);
+  // CHECK: store i32 500
+  gi = __builtin_object_size(arr, 2);
+  // CHECK: store i32 500
+  gi = __builtin_object_size(arr, 3);
+
+  // CHECK: store i32 100
+  gi = __builtin_object_size(malloc_function_pointer_with_typedef(100), 0);
+  // CHECK: store i32 100
+  gi = __builtin_object_size(malloc_function_pointer_with_typedef(100), 1);
+  // CHECK: store i32 100
+  gi = __builtin_object_size(malloc_function_pointer_with_typedef(100), 2);
+  // CHECK: store i32 100
+  gi = __builtin_object_size(malloc_function_pointer_with_typedef(100), 3);
+
+  // CHECK: store i32 500
+  gi = __builtin_object_size(calloc_function_pointer_with_typedef(100, 5), 0);
+  // CHECK: store i32 500
+  gi = __builtin_object_size(calloc_function_pointer_with_typedef(100, 5), 1);
+  // CHECK: store i32 500
+  gi = __builtin_object_size(calloc_function_pointer_with_typedef(100, 5), 2);
+  // CHECK: store i32 500
+  gi = __builtin_object_size(calloc_function_pointer_with_typedef(100, 5), 3);
+
+  void *const zeroPtr = malloc_function_pointer_with_typedef(0);
+  // CHECK: store i32 0
+  gi = __builtin_object_size(zeroPtr, 0);
+  // CHECK: store i32 0
+  gi = __builtin_object_size(malloc_function_pointer_with_typedef(0), 0);
+
+  void *const zeroArr1 = calloc_function_pointer_with_typedef(0, 1);
+  void *const zeroArr2 = calloc_function_pointer_with_typedef(1, 0);
+  // CHECK: store i32 0
+  gi = __builtin_object_size(zeroArr1, 0);
+  // CHECK: store i32 0
+  gi = __builtin_object_size(zeroArr2, 0);
+  // CHECK: store i32 0
+  gi = __builtin_object_size(calloc_function_pointer_with_typedef(1, 0), 0);
+  // CHECK: store i32 0
+  gi = __builtin_object_size(calloc_function_pointer_with_typedef(0, 1), 0);
+}

diff  --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
index fd56bd197586e..ddc4f73f1fd7c 100644
--- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -12,7 +12,6 @@
 // CHECK-NEXT: AcquireHandle (SubjectMatchRule_function, SubjectMatchRule_type_alias, SubjectMatchRule_variable_is_parameter)
 // CHECK-NEXT: Alias (SubjectMatchRule_function, SubjectMatchRule_variable_is_global)
 // CHECK-NEXT: AlignValue (SubjectMatchRule_variable, SubjectMatchRule_type_alias)
-// CHECK-NEXT: AllocSize (SubjectMatchRule_function)
 // CHECK-NEXT: AlwaysDestroy (SubjectMatchRule_variable)
 // CHECK-NEXT: AlwaysInline (SubjectMatchRule_function)
 // CHECK-NEXT: Annotate ()

diff  --git a/clang/test/Sema/alloc-size.c b/clang/test/Sema/alloc-size.c
index 56181511a1948..cd2673bd7ec7d 100644
--- a/clang/test/Sema/alloc-size.c
+++ b/clang/test/Sema/alloc-size.c
@@ -14,7 +14,7 @@ void *fail8(int a, int b) __attribute__((alloc_size(1, 3))); //expected-error{{'
 
 int fail9(int a) __attribute__((alloc_size(1))); //expected-warning{{'alloc_size' attribute only applies to return values that are pointers}}
 
-int fail10 __attribute__((alloc_size(1))); //expected-warning{{'alloc_size' attribute only applies to functions}}
+int fail10 __attribute__((alloc_size(1))); //expected-warning{{'alloc_size' attribute only applies to non-K&R-style functions}}
 
 void *fail11(void *a) __attribute__((alloc_size(1))); //expected-error{{'alloc_size' attribute argument may only refer to a function parameter of integer type}}
 
@@ -22,4 +22,39 @@ void *fail12(int a) __attribute__((alloc_size("abc"))); //expected-error{{'alloc
 void *fail12(int a) __attribute__((alloc_size(1, "abc"))); //expected-error{{'alloc_size' attribute requires parameter 2 to be an integer constant}}
 void *fail13(int a) __attribute__((alloc_size(1U<<31))); //expected-error{{integer constant expression evaluates to value 2147483648 that cannot be represented in a 32-bit signed integer type}}
 
-int (*PR31453)(int) __attribute__((alloc_size(1))); //expected-warning{{'alloc_size' attribute only applies to functions}}
+void *(*PR31453)(int)__attribute__((alloc_size(1)));
+
+void *KR() __attribute__((alloc_size(1))); //expected-warning{{'alloc_size' attribute only applies to non-K&R-style functions}}
+
+// Applying alloc_size to function pointers should work:
+void *(__attribute__((alloc_size(1))) * func_ptr1)(int);
+void *(__attribute__((alloc_size(1, 2))) func_ptr2)(int, int);
+
+// TODO: according to GCC documentation the following should actually be the type
+// “pointer to pointer to alloc_size attributed function returning void*” and should
+// therefore be supported
+void *(__attribute__((alloc_size(1))) **ptr_to_func_ptr)(int); // expected-warning{{'alloc_size' attribute only applies to non-K&R-style functions}}
+// The following definitions apply the attribute to the pointer to the function pointer which should not be possible
+void *(*__attribute__((alloc_size(1))) * ptr_to_func_ptr2)(int); // expected-warning{{'alloc_size' attribute only applies to non-K&R-style functions}}
+void *(**__attribute__((alloc_size(1))) ptr_to_func_ptr2)(int);  // expected-warning{{'alloc_size' attribute only applies to non-K&R-style functions}}
+
+// It should also work for typedefs:
+typedef void *(__attribute__((alloc_size(1))) allocator_function_typdef)(int);
+typedef void *(__attribute__((alloc_size(1, 2))) * allocator_function_typdef2)(int, int);
+void *(__attribute__((alloc_size(1, 2))) * allocator_function_typdef3)(int, int);
+// This typedef applies the alloc_size to the pointer to the function pointer and should not be allowed
+void *(**__attribute__((alloc_size(1, 2))) * allocator_function_typdef4)(int, int); // expected-warning{{'alloc_size' attribute only applies to non-K&R-style functions}}
+
+// We should not be warning when assigning function pointers with and without the alloc size attribute
+// since it doesn't change the type of the function
+typedef void *(__attribute__((alloc_size(1))) * my_malloc_fn_pointer_type)(int);
+typedef void *(*my_other_malloc_fn_pointer_type)(int);
+void *fn(int i);
+__attribute__((alloc_size(1))) void *fn2(int i);
+
+int main() {
+  my_malloc_fn_pointer_type f = fn;
+  my_other_malloc_fn_pointer_type f2 = fn;
+  my_malloc_fn_pointer_type f3 = fn2;
+  my_other_malloc_fn_pointer_type f4 = fn2;
+}


        


More information about the cfe-commits mailing list