https://gcc.gnu.org/g:4b0865a0562575358c93edac3d7c20a10422c628
commit r17-3896-g4b0865a0562575358c93edac3d7c20a10422c628 Author: Josef Melcr <[email protected]> Date: Mon Aug 10 16:56:32 2026 +0200 Reject variadic functions in callback_only attribute handler The attribute's implementation and handler assume that the described functions are not variadic. However, there were no checks for this in the attribute handler. That wasn't a major issue since the attribute wasn't available to users, but that is no longer the case. This patch adds the missing checks and documentation. gcc/c-family/ChangeLog: * c-attribs.cc (handle_callback_only_attribute): Reject variadic dispatching or callback functions. gcc/ChangeLog: * doc/extend.texi: Add a line saying variadic functions are unsupported to the callback_only description. gcc/testsuite/ChangeLog: * gcc.dg/attr-callback.c: Add testcases for variadic functions. Signed-off-by: Josef Melcr <[email protected]> Diff: --- gcc/c-family/c-attribs.cc | 20 +++++++++++++++++++- gcc/doc/extend.texi | 21 +++++++++++---------- gcc/testsuite/gcc.dg/attr-callback.c | 8 ++++++++ 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index b3d5407ec0b3..9e1fdc8087d9 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -4692,6 +4692,15 @@ handle_callback_only_attribute (tree *node, tree name, tree args, *no_add_attrs = true; } + tree decl_type = TREE_TYPE (decl); + if (stdarg_p (decl_type)) + { + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, + "%qE attribute cannot be used on variadic functions", name); + *no_add_attrs = true; + return NULL_TREE; + } + tree val = positional_argument (decl, name, TREE_VALUE (args), POINTER_TYPE, 1, POSARG_ZERO); if (!val) @@ -4704,7 +4713,7 @@ handle_callback_only_attribute (tree *node, tree name, tree args, /* We have to use the function type for validation, as DECL_ARGUMENTS returns NULL at this point. */ int callback_fn_idx = TREE_INT_CST_LOW (val); - tree decl_type_args = TYPE_ARG_TYPES (TREE_TYPE (decl)); + tree decl_type_args = TYPE_ARG_TYPES (decl_type); tree it; for (it = decl_type_args; it != NULL_TREE; it = TREE_CHAIN (it)) if (it == void_list_node) @@ -4738,6 +4747,15 @@ handle_callback_only_attribute (tree *node, tree name, tree args, } tree type_args = TYPE_ARG_TYPES (cfn_pointee_type); + + if (stdarg_p (cfn_pointee_type)) + { + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, + "%qE callback function cannot be variadic", name); + *no_add_attrs = true; + return NULL_TREE; + } + /* Compare the length of the list of argument indices and the real number of parameters the callback takes. */ unsigned cfn_nargs = list_length (TREE_CHAIN (args)); diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index a4981eb0debd..a9e4dfd5616d 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2358,30 +2358,31 @@ may be silently skipped when generating BTF. @cindex functions with callbacks @item callback_only The @code{callback_only} attribute specifies that the annotated function may -call the specified callback function. The first parameter identifies the index +call the specified callback function. The first parameter identifies the index of the callback function, the rest of the arguments specify the indices of the -arguments of the indirect call. All indices start from 1. If the function takes +arguments of the indirect call. All indices start from 1. If the function takes the implicit @code{this} pointer, it is referred to by the index 1, with the -rest of the arguments starting at index 2. The index 0 marks an argument not +rest of the arguments starting at index 2. The index 0 marks an argument not present in the arguments of the annotated function, an argument which is -modified before calling the callback function. The annotated function must pass +modified before calling the callback function. The annotated function must pass the specified arguments in the specified order to the callback function, which -must be callable with the number, order and type of the arguments. The +must be callable with the number, order and type of the arguments. The specified pointer to the callback may not escape the translation unit of the -annotated function and it may not be captured. The annotated function is +annotated function and it may not be captured. The annotated function is required to pass the arguments through, it may not change or dereference them. -The arguments also may not escape. The attribute may be used multiple times per +The arguments also may not escape. The attribute may be used multiple times per function, though only one @code{callback_only} attribute may be used per -function parameter. +function parameter. Neither the dispatching function nor the callback function +may be variadic. The attribute exposes the potentially hidden callsite in the annotated function, enabling interprocedural optimizations which may not be possible -without the attribute. It is most useful for annotating functions from +without the attribute. It is most useful for annotating functions from dynamically linked libraries, as their bodies are not available during compilation. This attribute is similar to the clang @code{callback} attribute but it is not -compatible with it. The clang implementation allows identifiers as arguments, +compatible with it. The clang implementation allows identifiers as arguments, marks an unknown argument with -1 and the @code{this} pointer with the index 0. An example usage: diff --git a/gcc/testsuite/gcc.dg/attr-callback.c b/gcc/testsuite/gcc.dg/attr-callback.c index 74c8287471bd..3837af1b1188 100755 --- a/gcc/testsuite/gcc.dg/attr-callback.c +++ b/gcc/testsuite/gcc.dg/attr-callback.c @@ -67,6 +67,14 @@ unknown_fn(char (*)(float*, double*), float*, double*, int*); /* { dg-warning "c void not_a_fn(int, int); /* { dg-warning "refers to" } */ +[[gnu::callback_only(1, 2)]] +void +vararg_1(void (*)(int*), int*, ...); /* { dg-warning "cannot be used on variadic functions" } */ + +[[gnu::callback_only(1, 2)]] +void +vararg_2(void (*)(int*, ...), int*); /* { dg-warning "callback function cannot be variadic" } */ + struct S { int x;
