On Sat, Jul 17, 2021 at 2:31 PM Segher Boessenkool
<seg...@kernel.crashing.org> wrote:
>
> Hi!
>
> On Fri, Jul 16, 2021 at 11:35:25AM -0700, apinski--- via Gcc-patches wrote:
> > --- a/gcc/c-family/c-common.c
> > +++ b/gcc/c-family/c-common.c
> > @@ -5799,7 +5799,7 @@ parse_optimize_options (tree args, bool attr_p)
> >
> >        if (TREE_CODE (value) == INTEGER_CST)
> >       {
> > -       char buffer[20];
> > +       char buffer[HOST_BITS_PER_LONG / 3 + 4];
> >         sprintf (buffer, "-O%ld", (long) TREE_INT_CST_LOW (value));
> >         vec_safe_push (optimize_args, ggc_strdup (buffer));
> >       }
>
> This calculation is correct, assuming "value" is non-negative.  You can
> easily avoid all of that though:

Actually it is still correct even for negative values because we are
adding 4 rather than 3 to make sure there is enough room for the sign
character.
So it takes 11 max characters for a signed 32bit integer
(ceil(log(2^31)) + 1) and add the "-O" part and the null character
gives us 14.  32/3 is 10, and then add 4 gives us 14. This is the
exact amount.
So it takes 20 max characters for a signed 64bit integer
(ceil(log(2^63)) + 1) and add the "-O" part and the null character
gives us 23.  64/3 is 21, and then add 4 gives us 25. There are 2
extra bytes used which is ok.


Thanks,
Andrew


>
>           int n = snprintf (0, 0, "-O%ld", (long) TREE_INT_CST_LOW (value));
>           char buffer[n + 1];
>           sprintf (buffer, "-O%ld", (long) TREE_INT_CST_LOW (value));
>           vec_safe_push (optimize_args, ggc_strdup (buffer));
>
> This creates a variable length allocation on the stack though.  You can
> do better (for some value of "better") by using the known longest value:
> (again assuming non-negative):
>
>           int n = snprintf (0, 0, "-O%ld", LONG_MAX);
>           char buffer[n + 1];
>           sprintf (buffer, "-O%ld", (long) TREE_INT_CST_LOW (value));
>           vec_safe_push (optimize_args, ggc_strdup (buffer));
>
> This does not call snprintf, GCC can evaluate that at compile time.
> This pattern works well in portable code.
>
> But we can do better still:
>
>           char *buffer;
>           asprintf (&buffer, "-O%ld", (long) TREE_INT_CST_LOW (value));
>           vec_safe_push (optimize_args, ggc_strdup (buffer));
>           free (buffer);
>
> (asprintf is in libiberty already).  And we could avoid the ggc_strdup
> if we made a variant of asprintf that marks the GGC itself (the aprintf
> implementation already factors calculating the length needed, it will
> be easy to do this).
>
>
> Segher

Reply via email to