[PATCH] handle VLA of zero length arrays and vice versa (PR 99121)

Jakub Jelinek jakub@redhat.com
Fri Mar 12 13:27:59 GMT 2021


On Mon, Mar 08, 2021 at 07:37:46PM -0700, Martin Sebor via Gcc-patches wrote:
> Accesses to zero-length arrays continue to be diagnosed (except for
> trailing arrays of unknown objects), as are nonempty accesses to empty
> types.
> 
> The warning message for (3) remains unchanged, i.e., for the following:
> 
>   struct S { } a[3];
> 
>   void g (int n)
>   {
>     ((int*)a)[0] = 0;
>   }
> 
> it's:
> 
>   warning: array subscript 0 is outside array bounds of ‘struct S[3]’
> [-Warray-bounds]

As I tried to explain several times, this is completely unacceptable to me.
We want to warn, I agree with that, but we don't care that we emit completely
nonsensical warning?
The user will be just confused by that, will (rightly) think it is a bug in
the compiler and might not fix the actual bug.
Array subscript 0 is not outside of those array bounds.

If you don't want a shortcut that for arrays with zero sized elements
and for non-array objects with zero size uses a different code path
that would just warn
"access outside of zero sized object %qD"
(which is what I'd prefer, any non-zero sized access to object of zero size
unless it is flexible array member or decl with flexible array member
is undefined, whatever offset you use)
and want to reuse the current code, at least please change reftype
to build_printable_array_type (TREE_TYPE (ref), 0);
so that it prints
warning: array subscript 0 is outside array bounds of ‘int[0]’ [-Warray-bounds]
You'll need to redo the:
          || !COMPLETE_TYPE_P (reftype)
          || TREE_CODE (TYPE_SIZE_UNIT (reftype)) != INTEGER_CST)
        return false;
check on the new reftype.
It should be done not just where you currently do:
                      nelts = integer_zero_node;
                      eltsize = 1;
but also somewhere in:
          eltsize = 1;
          tree size = TYPE_SIZE_UNIT (reftype);
          if (VAR_P (arg))
            if (tree initsize = DECL_SIZE_UNIT (arg))
              if (tree_int_cst_lt (size, initsize))
                size = initsize;

          arrbounds[1] = wi::to_offset (size);
below that for the case where integer_zerop (size) && TYPE_EMPTY_P (reftype).
There should be also:

  struct S { } a;

  void g (int n)
  {
    ((int*)&a)[0] = 0;
  }

testcase that covers that.

BTW, what is the reason behind the POINTER_TYPE_P check in:
      /* The type of the object being referred to.  It can be an array,
         string literal, or a non-array type when the MEM_REF represents
         a reference/subscript via a pointer to an object that is not
         an element of an array.  Incomplete types are excluded as well
         because their size is not known.  */
      reftype = TREE_TYPE (arg);
      if (POINTER_TYPE_P (reftype)
?
It disables the second warning on:
  __UINTPTR_TYPE__ a;
  void *b;

  void g (int n)
  {
    ((int*)&a)[4] = 0;
    ((int*)&b)[4] = 0;
  }

I really don't see what is different on vars with pointer type vs. vars with
non-pointer type of the same size for this warning.

	Jakub



More information about the Gcc-patches mailing list