[RFC PATCH] __builtin_va_arg_pack ()

Richard Guenther richard.guenther@gmail.com
Mon Sep 3 09:54:00 GMT 2007


On 8/31/07, Jakub Jelinek <jakub@redhat.com> wrote:
> On Fri, Aug 31, 2007 at 11:14:49AM +0200, Richard Guenther wrote:
> > 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.
>
> The -D_FORTIFY_SOURCE checking relies on inlining the wrappers.
> E.g. for sprintf we currently have:
> #define sprintf(str, ...) \
>   __builtin___sprintf_chk (str, __USE_FORTIFY_LEVEL - 1, __bos (str), \
>                            __VA_ARGS__)
> which can't be used in C++.  With the proposed __builtin_va_arg_pack ()
> it can be implemented as
> __extern_always_inline int
> sprintf (char *__restrict __s, __const char *__restrict __format, ...)
> {
>   return __builtin___sprintf_chk (__s, __USE_FORTIFY_LEVEL - 1, __bos (__s),
>                                   __format, __builtin_va_arg_pack ());
> }
> where
> #define __always_inline __inline __attribute__ ((__always_inline__))
> #define __extern_always_inline extern __always_inline __attribute__ ((__gnu_inline__))
> #define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1)
>
> If you instead want to call vsprintf, it couldn't be inlined:
> static inline int
> sprintf (char *__restrict __s, __const char *__restrict __format, ...)
> {
>   va_list __ap;
>   int __ret;
>   va_start (__ap, __format);
>   __ret = __builtin___vsprintf_chk (__s, __USE_FORTIFY_LEVEL - 1, __bos (__s),
>                                     __format, __ap);
>   va_end (__ap);
>   return __ret;
> }
> (at least, hacking up gcc so that it could inline this would be terribly
> difficult and extremely arch dependent), which unfortunately means
> that __builtin_object_size (__s, __USE_FORTIFY_LEVEL - 1) will
> always return -1UL - at least until we have ipa object size pass and cloning
> based on that (but the cloning would need to create a special out of
> line function for each different value of __bos, or figure it adds an
> artificial argument.  Even if it does, it is another hop the call to
> sprintf has to go through, so at least a few cycles wasted).
> But __bos (__s) == -1UL means no buffer overflow checking.
>
> >
> > > +                 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.
>
> You are right, fixed.  I wonder if there is a better method for copying
> the flags one by one, which is error prone.  We want to copy all the
> flags, except CALL_EXPR_VA_ARG_PACK and guess ann shouldn't be copied over
> either.  But doing
> CALL_EXPR_CHECK (new_call)->base = CALL_EXPR_CHECK (call)->base;
> sounds fragile too.

Yeah.  I think we should have explicit copying functions for all tree
codes ;)  Or
as a compromise a function that walks based on the tree code the
struct hierarchy
and copies all fields (or all flags only).  That way we would have one
central place
to update.

> BTW, OT, why isn't
> /* Used to mark a CALL_EXPR as not suitable for inlining.  */
> #define CALL_CANNOT_INLINE_P(NODE) ((NODE)->base.static_flag)
> using CALL_EXPR_CHECK?

I missed adding it.

> Here is an updated patch:

That looks good.  But I don't think I can approve it.  Still I'd like
to have it in
in 4.3 if it works out to support fortifying for C++.  So, Ian/Diego
can you have
a look here please?

Thanks!
Richard.

> 2007-08-31  Jakub Jelinek  <jakub@redhat.com>
>
>         * builtins.def (BUILT_IN_VA_ARG_PACK): New built-in.
>         * tree.h (CALL_EXPR_VA_ARG_PACK): Define.
>         * tree-inline.h (copy_body_data): Add call_expr field.
>         * tree-inline.c (expand_call_inline): Initialize call_expr.
>         (copy_bb): Append anonymous inline fn arguments to arguments
>         when inlining a CALL_EXPR_VA_ARG_PACK call.
>         * builtins.c (expand_builtin): Issue an error if
>         BUILT_IN_VA_ARG_PACK is seen during expand.
>         (fold_call_expr, fold_builtin_call_array): Don't fold
>         CALL_EXPR_VA_ARG_PACK CALL_EXPRs or calls with
>         __builtin_va_arg_pack () call as last argument.
>         * gimplify.c (gimplify_call_expr): If last argument to a vararg
>         function is __builtin_va_arg_pack (), decrease number of call
>         arguments and instead set CALL_EXPR_VA_ARG_PACK on the CALL_EXPR.
>         * expr.c (expand_expr_real_1): Issue an error if
>         CALL_EXPR_VA_ARG_PACK CALL_EXPR is seen during expand.
>         * tree-pretty-print.c (dump_generic_node): Handle printing
>         CALL_EXPR_VA_ARG_PACK bit on CALL_EXPRs.
>         * doc/extend.texi (__builtin_va_arg_pack): Document.
>
>         * gcc.c-torture/execute/va-arg-pack-1.c: New test.
>         * gcc.dg/va-arg-pack-1.c: New test.



More information about the Gcc-patches mailing list