[RFC PATCH] __builtin_va_arg_pack ()
Richard Guenther
richard.guenther@gmail.com
Fri Aug 31 10:19:00 GMT 2007
On 8/30/07, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> As I already wrote in
> http://gcc.gnu.org/ml/gcc-patches/2007-07/msg01033.html
> Alex's __attribute__((__gnu_inline__)) support for C++ allows glibc
> to implement most of the -D_FORTIFY_SOURCE fortification even for C++,
> with minimal changes, but there is a notable exception that *printf
> family of functions can't be protected that way.
> The problem is that these functions have variable number of arguments
> and for fortification we need to write trivial wrappers for them
> which can be inlined.
> For C we currently define these as macros, which has issues on its own,
> although it is permitted by POSIX, if using a function pointer
> with the same name as one of the functions one has to prevent
> expanding them as function-like macros, so say
> #include <stdio.h>
> ...
> foo->printf (a, b, c);
> won't compile while
> (foo->printf) (a, b, c);
> will. For C++ we can't use function-like macros here, because
> one can use the same identifier in his own namespace for different
> purpose.
>
> The following patch allows using inline functions for those cases,
> by introducing a __builtin_va_arg_pack () builtin which during
> inlining expands to all anonymous arguments of the inline function.
> It is similar to how __VA_ARGS__ can be used in the preprocessor,
> with a few limitations.
> Using it in an out-of-line function is an error, it doesn't make sense
> in that case, so it should be only used in always_inline inlines
> or gnu_inline extern inline functions (the latter, if it can't be inlined,
> will just result in an external call and that external implementation
> obviously can't use __builtin_va_arg_pack (), but the inline function
> can). Also, it can be only used in the context of anonymous arguments
> of another variable number of arguments call.
>
> What do you think about this?
I think the idea is sound. Though for instrumenting the standard functions
like printf couldn't you dispatch to the vprintf variants instead? I
see we'd need
to force the compiler to not inline that call then which works by re-declaring
it like
extern inline __attribute__((__gnu_inline__)) void foo(void) {}
extern inline __attribute__((__gnu_inline__)) void bar(void)
{
extern __attribute__((noinline)) void foo(void);
foo();
}
but unfortunately you get an extra warning for from that and further calls
to foo() outside of bar() are not inlined anymore. Leaving the only
other possibility to add a #pragma to mark a specific call as not-to-inline.
> + new_call = build_call_array (TREE_TYPE (call),
> + CALL_EXPR_FN (call),
> + nargs + call_expr_nargs (call),
> + argarray);
> + CALL_EXPR_STATIC_CHAIN (new_call)
> + = CALL_EXPR_STATIC_CHAIN (call);
> + CALL_EXPR_TAILCALL (new_call) = CALL_EXPR_TAILCALL (call);
> + CALL_EXPR_RETURN_SLOT_OPT (new_call)
> + = CALL_EXPR_RETURN_SLOT_OPT (call);
in tree.h I also find CALL_FROM_THUNK_P, CALL_CANNOT_INLINE_P and
TREE_NOTHROW.
> @@ -10413,14 +10419,26 @@ fold_call_expr (tree exp, bool ignore)
> tree fndecl = get_callee_fndecl (exp);
> if (fndecl
> && TREE_CODE (fndecl) == FUNCTION_DECL
> - && DECL_BUILT_IN (fndecl))
> + && DECL_BUILT_IN (fndecl)
> + && !CALL_EXPR_VA_ARG_PACK (exp))
> {
> + int nargs = call_expr_nargs (exp);
> +
> + if (nargs && TREE_CODE (CALL_EXPR_ARG (exp, nargs - 1)) == CALL_EXPR)
> + {
> + tree fndecl2 = get_callee_fndecl (CALL_EXPR_ARG (exp, nargs - 1));
> + if (fndecl2
> + && TREE_CODE (fndecl2) == FUNCTION_DECL
> + && DECL_BUILT_IN (fndecl2)
> + && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK)
> + return NULL_TREE;
> + }
> +
I think this needs a comment explaining what is happening. Also for all places
you check DECL_BUILT_IN and DECL_FUNCTION_CODE for
BUILT_IN_VA_ARG_PACK you need to check the DECL_BUILT_IN_CLASS
for BUILT_IN_NORMAL.
> @@ -10506,6 +10524,15 @@ fold_builtin_call_array (tree type,
> if (TREE_CODE (fndecl) == FUNCTION_DECL
> && DECL_BUILT_IN (fndecl))
> {
> + if (n && TREE_CODE (argarray[n - 1]) == CALL_EXPR)
> + {
> + tree fndecl2 = get_callee_fndecl (argarray[n - 1]);
> + if (fndecl2
> + && TREE_CODE (fndecl2) == FUNCTION_DECL
> + && DECL_BUILT_IN (fndecl2)
> + && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK)
> + return build_call_array (type, fn, n, argarray);
> + }
Likewise.
> +@smallexample
> +extern inline __attribute__ ((__always_inline__)) int
I think this example should use __gnu_inline__ attribute.
Richard.
More information about the Gcc-patches
mailing list