On Tue, 21 Mar 2023, Jakub Jelinek wrote:

> Hi!
> 
> Our documentation sadly talks about elt_type arr[0]; as zero-length arrays,
> not arrays with zero elements.  Unfortunately, those aren't the only arrays
> which can have zero size, the same size can be also result of zero-length
> element, like in GNU C struct whatever {} or in GNU C/C++ if the element
> type is [0] array or combination thereof (dunno if Ada doesn't allow
> something similar too).  One can't do much with them, taking address of
> their elements, (no-op) copying of the elements in and out.  But they
> behave differently from arr[0] arrays e.g. in that using non-zero indexes
> in them (as long as they are within bounds as for normal arrays) is valid.
> 
> I think this naming inaccuracy resulted in Martin designing
> special_array_member in an inconsistent way, mixing size zero array members
> with array members of one or two or more elements and then using the
> size zero interchangeably with zero elements.
> 
> The following patch changes that (but doesn't do any
> documentation/diagnostics renaming, as this is really a corner case),
> such that int_0/trail_0 for consistency is just about [0] arrays
> plus [] for the latter, not one or more zero sized elements case.
> 
> The testcase has one xfailed case for where perhaps in later GCC versions
> we could add extra code to handle it, for some reason we don't diagnose
> out of bounds accesses for the zero sized elements cases.  It will be
> harder because e.g. FRE will canonicalize &var.fld[0] and &var.fld[10]
> to just one of them because they are provably the same address.
> But the important thing is to fix this regression (where we warn on
> completely valid code in the Linux kernel).  Anyway, for further work
> on this we don't really need any extra help from special_array_member,
> all code can just check integer_zerop (TYPE_SIZE_UNIT (TREE_TYPE (type))),
> it doesn't depend on the position of the members etc.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

Thanks,
Richard.

> 2023-03-21  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR tree-optimization/109215
>       * tree.h (enum special_array_member): Adjust comments for int_0
>       and trail_0.
>       * tree.cc (component_ref_sam_type): Clear zero_elts if memtype
>       has zero sized element type and the array has variable number of
>       elements or constant one or more elements.
>       (component_ref_size): Adjust comments, formatting fix.
> 
>       * gcc.dg/Wzero-length-array-bounds-3.c: New test.
> 
> --- gcc/tree.h.jj     2023-03-14 19:11:52.296936422 +0100
> +++ gcc/tree.h        2023-03-20 18:48:23.068788830 +0100
> @@ -5579,8 +5579,8 @@ extern tree component_ref_field_offset (
>  enum struct special_array_member
>    {
>      none,    /* Not a special array member.  */
> -    int_0,   /* Interior array member with size zero.  */
> -    trail_0, /* Trailing array member with size zero.  */
> +    int_0,   /* Interior array member with zero elements.  */
> +    trail_0, /* Trailing array member with zero elements.  */
>      trail_1, /* Trailing array member with one element.  */
>      trail_n, /* Trailing array member with two or more elements.  */
>      int_n    /* Interior array member with one or more elements.  */
> --- gcc/tree.cc.jj    2023-03-10 10:38:46.551473829 +0100
> +++ gcc/tree.cc       2023-03-20 19:41:35.605580732 +0100
> @@ -13032,14 +13032,27 @@ component_ref_sam_type (tree ref)
>       return sam_type;
>  
>        bool trailing = false;
> -      (void)array_ref_flexible_size_p (ref, &trailing);
> -      bool zero_length = integer_zerop (memsize);
> -      if (!trailing && !zero_length)
> -     /* MEMBER is an interior array with
> -       more than one element.  */
> +      (void) array_ref_flexible_size_p (ref, &trailing);
> +      bool zero_elts = integer_zerop (memsize);
> +      if (zero_elts && integer_zerop (TYPE_SIZE_UNIT (TREE_TYPE (memtype))))
> +     {
> +       /* If array element has zero size, verify if it is a flexible
> +          array member or zero length array.  Clear zero_elts if
> +          it has one or more members or is a VLA member.  */
> +       if (tree dom = TYPE_DOMAIN (memtype))
> +         if (tree min = TYPE_MIN_VALUE (dom))
> +           if (tree max = TYPE_MAX_VALUE (dom))
> +             if (TREE_CODE (min) != INTEGER_CST
> +                 || TREE_CODE (max) != INTEGER_CST
> +                 || !((integer_zerop (min) && integer_all_onesp (max))
> +                      || tree_int_cst_lt (max, min)))
> +               zero_elts = false;
> +     }
> +      if (!trailing && !zero_elts)
> +     /* MEMBER is an interior array with more than one element.  */
>       return special_array_member::int_n;
>  
> -      if (zero_length)
> +      if (zero_elts)
>       {
>         if (trailing)
>           return special_array_member::trail_0;
> @@ -13047,7 +13060,7 @@ component_ref_sam_type (tree ref)
>           return special_array_member::int_0;
>       }
>  
> -      if (!zero_length)
> +      if (!zero_elts)
>       if (tree dom = TYPE_DOMAIN (memtype))
>         if (tree min = TYPE_MIN_VALUE (dom))
>           if (tree max = TYPE_MAX_VALUE (dom))
> @@ -13114,14 +13127,14 @@ component_ref_size (tree ref, special_ar
>  
>        tree afield_decl = TREE_OPERAND (ref, 1);
>        gcc_assert (TREE_CODE (afield_decl) == FIELD_DECL);
> -      /* if the trailing array is a not a flexible array member, treat it as
> +      /* If the trailing array is a not a flexible array member, treat it as
>        a normal array.  */
>        if (DECL_NOT_FLEXARRAY (afield_decl)
>         && *sam != special_array_member::int_0)
>       return memsize;
>  
>        if (*sam == special_array_member::int_0)
> -       memsize = NULL_TREE;
> +     memsize = NULL_TREE;
>  
>        /* For a reference to a flexible array member of a union
>        use the size of the union instead of the size of the member.  */
> @@ -13129,7 +13142,7 @@ component_ref_size (tree ref, special_ar
>       memsize = TYPE_SIZE_UNIT (argtype);
>      }
>  
> -  /* MEMBER is either a bona fide flexible array member, or a zero-length
> +  /* MEMBER is either a bona fide flexible array member, or a zero-elements
>       array member, or an array of length one treated as such.  */
>  
>    /* If the reference is to a declared object and the member a true
> --- gcc/testsuite/gcc.dg/Wzero-length-array-bounds-3.c.jj     2023-03-20 
> 19:17:21.290648885 +0100
> +++ gcc/testsuite/gcc.dg/Wzero-length-array-bounds-3.c        2023-03-20 
> 19:16:48.494123583 +0100
> @@ -0,0 +1,19 @@
> +/* PR tree-optimization/109215 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -Wall" } */
> +
> +struct S {};
> +struct T { struct S s[3]; struct S t; };
> +void foo (struct S *);
> +
> +void
> +bar (struct T *t)
> +{
> +  foo (&t->s[2]);    /* { dg-bogus "array subscript 2 is outside the bounds 
> of an interior zero-length array" } */
> +}
> +
> +void
> +baz (struct T *t)
> +{
> +  foo (&t->s[3]);    /* { dg-error "" "" { xfail *-*-* } } */
> +}
> 
>       Jakub
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
HRB 36809 (AG Nuernberg)

Reply via email to