https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123160

            Bug ID: 123160
           Summary: pointer_plus folding breaks objsz
           Product: gcc
           Version: 16.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: amacleod at redhat dot com
  Target Milestone: ---
            Target: x86_64-pc-linux-gnu

Created attachment 63066
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=63066&action=edit
testcase

The attached testcase demonstrates that gimple_fold of a pointer_plus
expression can result in a loss of information.
struct A
{
  char a[10];
  int b;
  char c[10];
} a;

The passing function:

int
passes (void)
{
  void *r;
  r = &a.a[4];
  r = memset (r, 'a', 2);
  r = memset (r + 2, 'b', 2) + 2;
  if (__builtin_object_size (r, 3) != sizeof (a.a) - 8)
    __builtin_abort ();
}

obfuscates r enough that optimization doesn't do much, and the objsz pass can
walk the use def chains and figure out that the call to abort() can be
eliminated, resulting in
  r_5 = memset (&a.a[4], 97, 2);
  _1 = r_5 + 2;
  memset (_1, 98, 2);

The fails () function simply removes the first memset.  This allows the
expression &a.a[4] + 2 to be folded into a generic
   &MEM <char> [(void *)&a + 6B]
which loses the information that it points to the a[10] object, and now refers
to the containing struct A.
This causes the objsz pass to use the size of the structure instead of the
array and the call to abort becomes always called.  This results in:
  <bb 2> [count: 0]:
  memset (&MEM <char> [(void *)&a + 6B], 98, 2);
  __builtin_abort ();

I believe this is due to the way gimple_fold_stmt_to_constant_1 handles the
POINTER_PLUS_EXPR case by simply generating the MEM.

This fails back to at least GCC 13

Reply via email to