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

            Bug ID: 92312
           Summary: bogus -Wstringop-overflow storing into a trailing
                    array backed by larger buffer
           Product: gcc
           Version: 10.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: middle-end
          Assignee: unassigned at gcc dot gnu.org
          Reporter: msebor at gcc dot gnu.org
  Target Milestone: ---

GCC 10.0 issues a -Wstringop-overflow warning for stores into trailing arrays
that are backed by a large enough buffer to act as larger "flexible array
members."  This is a safe idiom that should probably be allowed without a
warning.  It's used for example in the Linux kernel where it triggers the
following warning (and a few others):

drivers/input/mouse/cyapa_gen5.c:1559:34: warning: writing 1 byte into a region
of size 0 [-Wstringop-overflow=]
 1559 |  app_cmd_head->parameter_data[0] = GEN5_PARAMETER_DISABLE_PIP_REPORT;
      |                                  ^
drivers/input/mouse/cyapa_gen5.c: In function ‘cyapa_gen5_set_power_mode’:
drivers/input/mouse/cyapa_gen5.c:317:5: note: at offset 0 to object
‘parameter_data’ with size 0 declared here
  317 |  u8 parameter_data[0];  /* Parameter data variable based on cmd_code */
      |     ^~~~~~~~~~~~~~

A small test case is below.

$ cat z.c && gcc -O2 -S -Wall -fdump-tree-strlen=/dev/stdout z.c
struct S0 { char a, b[0]; };

void f0 (void*);

void f1 (void)
{
  char a[3];
  struct S0 *p = (struct S0*)a;
  p->a = 0;
  __builtin_memset (p->b, 0, 2);   // ok
  f0 (p);
}

void f2 (void)
{
  char a[3];
  struct S0 *p = (struct S0*)a;
  p->a = 0;
  p->b[0] = 0;
  p->b[1] = 1;                     // warning
  f0 (p);
}

struct Sx { char a, b[]; };

void f3 (void)
{
  char a[3];
  struct Sx *p = (struct Sx*)a;
  p->a = 0;
  p->b[0] = 0;
  p->b[1] = 1;                     // warning
  f0 (p);
}


;; Function f1 (f1, funcdef_no=0, decl_uid=1935, cgraph_uid=1, symbol_order=0)

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2
;; 2 succs { 1 }
f1 ()
{
  char a[3];

  <bb 2> [local count: 1073741824]:
  MEM[(struct S0 *)&a].a = 0;
  __builtin_memset (&MEM <char[0:]> [(void *)&a + 1B], 0, 2);
  f0 (&a);
  a ={v} {CLOBBER};
  return;

}



;; Function f2 (f2, funcdef_no=1, decl_uid=1940, cgraph_uid=2, symbol_order=1)

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2
;; 2 succs { 1 }
z.c: In function ‘f2’:
z.c:19:11: warning: writing 1 byte into a region of size 0
[-Wstringop-overflow=]
   19 |   p->b[0] = 0;
      |   ~~~~~~~~^~~
z.c:1:21: note: destination object declared here
    1 | struct S0 { char a, b[0]; };
      |                     ^
z.c:20:11: warning: writing 1 byte into a region of size 0
[-Wstringop-overflow=]
   20 |   p->b[1] = 1;                     // warning
      |   ~~~~~~~~^~~
z.c:1:21: note: destination object declared here
    1 | struct S0 { char a, b[0]; };
      |                     ^
f2 ()
{
  char a[3];

  <bb 2> [local count: 1073741824]:
  MEM[(struct S0 *)&a].a = 0;
  MEM[(struct S0 *)&a].b[0] = 0;
  MEM[(struct S0 *)&a].b[1] = 1;
  f0 (&a);
  a ={v} {CLOBBER};
  return;

}



;; Function f3 (f3, funcdef_no=2, decl_uid=1948, cgraph_uid=3, symbol_order=2)

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2
;; 2 succs { 1 }
z.c: In function ‘f3’:
z.c:31:11: warning: writing 1 byte into a region of size 0
[-Wstringop-overflow=]
   31 |   p->b[0] = 0;
      |   ~~~~~~~~^~~
z.c:24:21: note: destination object declared here
   24 | struct Sx { char a, b[]; };
      |                     ^
z.c:32:11: warning: writing 1 byte into a region of size 0
[-Wstringop-overflow=]
   32 |   p->b[1] = 1;                     // warning
      |   ~~~~~~~~^~~
z.c:24:21: note: destination object declared here
   24 | struct Sx { char a, b[]; };
      |                     ^
f3 ()
{
  char a[3];

  <bb 2> [local count: 1073741824]:
  MEM[(struct Sx *)&a].a = 0;
  MEM[(struct Sx *)&a].b[0] = 0;
  MEM[(struct Sx *)&a].b[1] = 1;
  f0 (&a);
  a ={v} {CLOBBER};
  return;

}

Reply via email to