On Wed, Feb 05, 2025 at 12:59:58PM +0100, Jakub Jelinek wrote:
> Hi!
> 
> Kees, any progress on this?

Hi!

I need to take another run at it. I got stalled out when I discovered
that I array-of-char-arrays attributes got applied at the "wrong" depth,
and stuff wasn't working.

e.g.:

char acpi_table[TABLE_SIZE][4] __attribute((nonstring)) = {
        { "ohai" },
        { "1234" },
};

when nonstring was checked for on something like "acpi_table[2]" it
wouldn't be found, since it was applied at the top level.

> 
> On Mon, Jan 06, 2025 at 04:34:27PM -0500, Marek Polacek wrote:
> > > -         pedwarn_init (init_loc, 0,
> > > -                       ("initializer-string for array of %qT "
> > > -                        "is too long"), typ1);
> > > -       else if (warn_unterminated_string_initialization
> > > -                && compare_tree_int (TYPE_SIZE_UNIT (type), len) < 0)
> > > -         warning_at (init_loc, OPT_Wunterminated_string_initialization,
> > > -                     ("initializer-string for array of %qT "
> > > -                      "is too long"), typ1);
> > > +
> > >         if (compare_tree_int (TYPE_SIZE_UNIT (type), len) < 0)
> > >           {
> > > -           unsigned HOST_WIDE_INT size
> > > -             = tree_to_uhwi (TYPE_SIZE_UNIT (type));
> > > -           const char *p = TREE_STRING_POINTER (inside_init);
> > > -
> > > -           inside_init = build_string (size, p);
> > > +            unsigned HOST_WIDE_INT avail
> > > +              = tree_to_uhwi (TYPE_SIZE_UNIT (type));
> > > +            unsigned unit = TYPE_PRECISION (typ1) / BITS_PER_UNIT;
> > > +            const char *p = TREE_STRING_POINTER (inside_init);
> > > +
> > > +            /* Construct truncated string.  */
> > > +            inside_init = build_string (avail, p);
> > > +
> > > +            /* Subtract the size of a single (possibly wide) character
> > > +               because it may be ok to ignore the terminating NUL char
> > > +               that is counted in the length of the constant.  */
> > > +            if (warn_cxx_compat || len - unit > avail)
> > > +              {
> > > +                 pedwarn_init (init_loc, 0,
> > > +                               ("initializer-string for array of %qT "
> > > +                                "is too long (%lu chars into %lu "
> > > +                                "available)"), typ1, len, avail);
> > > +              }
> > 
> > No need for the { } here.
> 
> The indentation is wrong in the whole block.
> The { after compare_tree_int is indented by 2 tabs (so 16 columns), but
> unsigned HOST_WIDE_INT avail already by 2 tabs and 3 spaces rather than
> 2 tabs and 2 spaces.  So it is one column more right than it should be.
> 
> Anyway, more importantly, the "warn_cxx_compat || " part looks wrong.
> For -Wc++-compat we should (perhaps with slightly different wording)
> preserve the GCC 14 behavior, which was
>             /* Subtract the size of a single (possibly wide) character
>                because it's ok to ignore the terminating null char
>                that is counted in the length of the constant.  */
>             if (compare_tree_int (TYPE_SIZE_UNIT (type), len - unit) < 0)
>               pedwarn_init (init_loc, 0,
>                             ("initializer-string for array of %qT "
>                              "is too long"), typ1);
>             else if (warn_cxx_compat
>                      && compare_tree_int (TYPE_SIZE_UNIT (type), len) < 0)
>               warning_at (init_loc, OPT_Wc___compat,
>                           ("initializer-string for array of %qT "
>                            "is too long for C++"), typ1);
> So, if (len - unit > avail) do the pedwarn_init (also note that %lu is
> wrong for unsigned HOST_WIDE_INT, one should use %wu instead; or for the
> avail case one could just print %E and pass it TYPE_SIZE_UNIT (type);
> unsigned HOST_WIDE_INT doesn't have to be unsigned long, it can be also
> unsigned long long).  And if warn_cxx_compat, do warning_at, IMNSHO
> with OPT_Wc___compat, with the "is too long for C++" substring in it
> and perhaps some more details (len and avail too).
> 
> Though, perhaps we should also change
> C ObjC Var(warn_unterminated_string_initialization) Warning LangEnabledBy(C 
> ObjC,Wextra || Wc++-compat)
> to
> C ObjC Var(warn_unterminated_string_initialization) Warning LangEnabledBy(C 
> ObjC,Wextra)
> and adjust documentation, because say
> -Wno-unterminated-string-initialization will no longer turn off that
> warning, essentially -Wc++-compat and -Wunterminated-string-initialization
> are then independent warnings with -Wc++-compat having priority over the
> latter.
> Or we could guard it with
> warn_cxx_compat && warn_unterminated_string_initialization
> but then the question is what to pass to second warning_at option,
> because one needs both.
> So, I think it is better to keep -Wc++-compat working as before (perhaps
> with the extra descriptions of the two lengths) and then have this new
> -Wunterminated-string-initialization warning implied by -Wextra which
> does nothing in the rare case when -Wc++-compat is on, and otherwise
> does the new stuff of warning except when initializing nonstring
> objects.

Okay, I will take a stab at getting this reorganized. Thanks for the
review!

-- 
Kees Cook

Reply via email to