Bug 95140 - [12/13/14/15 Regression] bogus -Wstringop-overflow for a loop unrolled past the end of an array
Summary: [12/13/14/15 Regression] bogus -Wstringop-overflow for a loop unrolled past t...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 10.0
: P2 normal
Target Milestone: 12.5
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic, missed-optimization
: 103956 (view as bug list)
Depends on:
Blocks: Wstringop-overflow
  Show dependency treegraph
 
Reported: 2020-05-14 19:19 UTC by Martin Sebor
Modified: 2024-07-19 13:07 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 10.1.0, 11.0
Last reconfirmed: 2020-05-14 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Sebor 2020-05-14 19:19:14 UTC
As reported in https://bugzilla.redhat.com/show_bug.cgi?id=1835906, compiling loops that copy a variable number of elements to a trailing character array member results in many spurious instances of -Wstringop-overflow (below).

The reporter expects "No warnings about an overflow, and little or no code to handle c > 8, as that would be undefined behaviour" and adds "It would be nice if GCC still warned if a function like f was called with a value of c that was a compile time constant > 8 however."

$ cat rhbz1835906.c && gcc -O3 -S -Wall -fdump-tree-strlen=/dev/stdout rhbz1835906.c
struct A
{
  char v[8];
};

void f (struct A *p, char * s, int c)
{
  for (int i = 0; i < c; ++i)
    p->v[i] = s[i];
}

;; Function f (f, funcdef_no=0, decl_uid=1934, cgraph_uid=1, symbol_order=0)

Created preheader block for loop 2
Created preheader block for loop 1
;; 4 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2 3 4 28 5 30 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 27 23 29 24 25 26
;;
;; Loop 2
;;  header 23, latch 29
;;  depth 1, outer 0
;;  nodes: 23 29
;;
;; Loop 1
;;  header 5, latch 30
;;  depth 1, outer 0
;;  nodes: 5 30
;; 2 succs { 3 26 }
;; 3 succs { 14 4 }
;; 4 succs { 28 6 }
;; 28 succs { 5 }
;; 5 succs { 30 6 }
;; 30 succs { 5 }
;; 6 succs { 7 24 }
;; 7 succs { 8 24 }
;; 8 succs { 9 24 }
;; 9 succs { 10 24 }
;; 10 succs { 11 24 }
;; 11 succs { 12 24 }
;; 12 succs { 13 24 }
;; 13 succs { 24 }
;; 14 succs { 15 25 }
;; 15 succs { 16 25 }
;; 16 succs { 17 25 }
;; 17 succs { 18 25 }
;; 18 succs { 19 25 }
;; 19 succs { 20 25 }
;; 20 succs { 21 25 }
;; 21 succs { 22 25 }
;; 22 succs { 27 25 }
;; 27 succs { 23 }
;; 23 succs { 29 25 }
;; 29 succs { 23 }
;; 24 succs { 25 }
;; 25 succs { 26 }
;; 26 succs { 1 }
rhbz1835906.c: In function ‘f’:
rhbz1835906.c:9:13: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
    9 |     p->v[i] = s[i];
      |     ~~~~~~~~^~~~~~
rhbz1835906.c:3:8: note: at offset [8, 2147483640] to object ‘v’ with size 8 declared here
    3 |   char v[8];
      |        ^
rhbz1835906.c:9:13: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
    9 |     p->v[i] = s[i];
      |     ~~~~~~~~^~~~~~
rhbz1835906.c:3:8: note: at offset [9, 2147483641] to object ‘v’ with size 8 declared here
    3 |   char v[8];
      |        ^
rhbz1835906.c:9:13: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
    9 |     p->v[i] = s[i];
      |     ~~~~~~~~^~~~~~
rhbz1835906.c:3:8: note: at offset [10, 2147483642] to object ‘v’ with size 8 declared here
    3 |   char v[8];
      |        ^
rhbz1835906.c:9:13: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
    9 |     p->v[i] = s[i];
      |     ~~~~~~~~^~~~~~
rhbz1835906.c:3:8: note: at offset [11, 2147483643] to object ‘v’ with size 8 declared here
    3 |   char v[8];
      |        ^
rhbz1835906.c:9:13: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
    9 |     p->v[i] = s[i];
      |     ~~~~~~~~^~~~~~
rhbz1835906.c:3:8: note: at offset [12, 2147483644] to object ‘v’ with size 8 declared here
    3 |   char v[8];
      |        ^
rhbz1835906.c:9:13: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
    9 |     p->v[i] = s[i];
      |     ~~~~~~~~^~~~~~
rhbz1835906.c:3:8: note: at offset [13, 2147483645] to object ‘v’ with size 8 declared here
    3 |   char v[8];
      |        ^
rhbz1835906.c:9:13: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
    9 |     p->v[i] = s[i];
      |     ~~~~~~~~^~~~~~
rhbz1835906.c:3:8: note: at offset [14, 2147483646] to object ‘v’ with size 8 declared here
    3 |   char v[8];
      |        ^
rhbz1835906.c:9:13: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
    9 |     p->v[i] = s[i];
      |     ~~~~~~~~^~~~~~
rhbz1835906.c:3:8: note: at offset 8 to object ‘v’ with size 8 declared here
    3 |   char v[8];
      |        ^
f (struct A * p, char * s, int c)
{
  unsigned long ivtmp.24;
  sizetype ivtmp.15;
  vector(8) char * vectp_p.12;
  vector(8) char * vectp_p.11;
  vector(8) char vect__3.10;
  vector(8) char * vectp_s.9;
  vector(8) char * vectp_s.8;
  int tmp.7;
  unsigned int niters_vector_mult_vf.6;
  unsigned int bnd.5;
  unsigned int niters.4;
  int i;
  unsigned int _4;
  unsigned int _5;
  char _11;
  ssizetype _12;
  char * _13;
  _Bool _17;
  sizetype _19;
  _Bool _20;
  _Bool _21;
  char _26;
  sizetype _33;
  char * _34;
  char _35;
  char _54;
  char * _60;
  char _61;
  char * _67;
  char _68;
  char * _74;
  char _75;
  char * _81;
  char _82;
  char * _88;
  char _89;
  char * _95;
  char _96;
  char * _102;
  char _103;
  sizetype _108;
  char * _109;
  char _110;
  sizetype _115;
  char * _116;
  char _117;
  sizetype _122;
  char * _123;
  char _124;
  sizetype _129;
  char * _130;
  char _131;
  sizetype _136;
  char * _137;
  char _138;
  sizetype _143;
  char * _144;
  char _145;
  unsigned int _159;
  unsigned int _160;

  <bb 2> [local count: 118111600]:
  if (c_7(D) > 0)
    goto <bb 3>; [89.00%]
  else
    goto <bb 26>; [11.00%]

  <bb 3> [local count: 105119324]:
  _5 = (unsigned int) c_7(D);
  _4 = _5 + 4294967295;
  _17 = _4 > 6;
  _13 = s_8(D) + 1;
  _12 = p_9(D) - _13;
  _19 = (sizetype) _12;
  _20 = _19 > 6;
  _21 = _20 & _17;
  if (_21 != 0)
    goto <bb 4>; [80.00%]
  else
    goto <bb 14>; [20.00%]

  <bb 4> [local count: 84095460]:
  bnd.5_39 = _5 >> 3;
  vect__3.10_152 = MEM <vector(8) char> [(char *)s_8(D)];
  MEM <vector(8) char> [(char *)p_9(D)] = vect__3.10_152;
  vectp_s.8_154 = s_8(D) + 8;
  vectp_p.11_155 = p_9(D) + 8;
  if (bnd.5_39 > 1)
    goto <bb 28>; [83.33%]
  else
    goto <bb 6>; [16.67%]

  <bb 28> [local count: 70079550]:

  <bb 5> [local count: 70079549]:
  # ivtmp.24_148 = PHI <0(28), ivtmp.24_158(30)>
  vect__3.10_45 = MEM[base: s_8(D), index: ivtmp.24_148, step: 8, offset: 8B];
  MEM[base: p_9(D), index: ivtmp.24_148, step: 8, offset: 8B] = vect__3.10_45;
  ivtmp.24_158 = ivtmp.24_148 + 1;
  _159 = (unsigned int) ivtmp.24_158;
  _160 = _159 + 1;
  if (_160 < bnd.5_39)
    goto <bb 30>; [83.33%]
  else
    goto <bb 6>; [16.67%]

  <bb 30> [local count: 58399624]:
  goto <bb 5>; [100.00%]

  <bb 6> [local count: 84095460]:
  niters_vector_mult_vf.6_40 = bnd.5_39 << 3;
  tmp.7_41 = (int) niters_vector_mult_vf.6_40;
  if (_5 == niters_vector_mult_vf.6_40)
    goto <bb 24>; [12.50%]
  else
    goto <bb 7>; [87.50%]

  <bb 7> [local count: 73583527]:
  _108 = (sizetype) tmp.7_41;
  _109 = s_8(D) + _108;
  _110 = *_109;
  p_9(D)->v[tmp.7_41] = _110;
  i_112 = tmp.7_41 + 1;
  if (c_7(D) > i_112)
    goto <bb 8>; [89.00%]
  else
    goto <bb 24>; [11.00%]

  <bb 8> [local count: 65489342]:
  _115 = (sizetype) i_112;
  _116 = s_8(D) + _115;
  _117 = *_116;
  p_9(D)->v[i_112] = _117;
  i_119 = i_112 + 1;
  if (c_7(D) > i_119)
    goto <bb 9>; [89.00%]
  else
    goto <bb 24>; [11.00%]

  <bb 9> [local count: 58285513]:
  _122 = (sizetype) i_119;
  _123 = s_8(D) + _122;
  _124 = *_123;
  p_9(D)->v[i_119] = _124;
  i_126 = i_119 + 1;
  if (c_7(D) > i_126)
    goto <bb 10>; [89.00%]
  else
    goto <bb 24>; [11.00%]

  <bb 10> [local count: 51874105]:
  _129 = (sizetype) i_126;
  _130 = s_8(D) + _129;
  _131 = *_130;
  p_9(D)->v[i_126] = _131;
  i_133 = i_126 + 1;
  if (c_7(D) > i_133)
    goto <bb 11>; [89.00%]
  else
    goto <bb 24>; [11.00%]

  <bb 11> [local count: 46167954]:
  _136 = (sizetype) i_133;
  _137 = s_8(D) + _136;
  _138 = *_137;
  p_9(D)->v[i_133] = _138;
  i_140 = i_133 + 1;
  if (c_7(D) > i_140)
    goto <bb 12>; [89.00%]
  else
    goto <bb 24>; [11.00%]

  <bb 12> [local count: 41089477]:
  _143 = (sizetype) i_140;
  _144 = s_8(D) + _143;
  _145 = *_144;
  p_9(D)->v[i_140] = _145;
  i_147 = i_140 + 1;
  if (c_7(D) > i_147)
    goto <bb 13>; [89.00%]
  else
    goto <bb 24>; [11.00%]

  <bb 13> [local count: 36569637]:
  _33 = (sizetype) i_147;
  _34 = s_8(D) + _33;
  _35 = *_34;
  p_9(D)->v[i_147] = _35;
  i_37 = i_147 + 1;
  goto <bb 24>; [100.00%]

  <bb 14> [local count: 21023864]:
  _11 = *s_8(D);
  p_9(D)->v[0] = _11;
  if (c_7(D) > 1)
    goto <bb 15>; [89.00%]
  else
    goto <bb 25>; [11.00%]

  <bb 15> [local count: 18711240]:
  _54 = *_13;
  p_9(D)->v[1] = _54;
  if (c_7(D) > 2)
    goto <bb 16>; [89.00%]
  else
    goto <bb 25>; [11.00%]

  <bb 16> [local count: 16653003]:
  _60 = s_8(D) + 2;
  _61 = *_60;
  p_9(D)->v[2] = _61;
  if (c_7(D) > 3)
    goto <bb 17>; [89.00%]
  else
    goto <bb 25>; [11.00%]

  <bb 17> [local count: 14821173]:
  _67 = s_8(D) + 3;
  _68 = *_67;
  p_9(D)->v[3] = _68;
  if (c_7(D) > 4)
    goto <bb 18>; [89.00%]
  else
    goto <bb 25>; [11.00%]

  <bb 18> [local count: 13190844]:
  _74 = s_8(D) + 4;
  _75 = *_74;
  p_9(D)->v[4] = _75;
  if (c_7(D) > 5)
    goto <bb 19>; [89.00%]
  else
    goto <bb 25>; [11.00%]

  <bb 19> [local count: 11739850]:
  _81 = s_8(D) + 5;
  _82 = *_81;
  p_9(D)->v[5] = _82;
  if (c_7(D) > 6)
    goto <bb 20>; [89.00%]
  else
    goto <bb 25>; [11.00%]

  <bb 20> [local count: 10448467]:
  _88 = s_8(D) + 6;
  _89 = *_88;
  p_9(D)->v[6] = _89;
  if (c_7(D) > 7)
    goto <bb 21>; [89.00%]
  else
    goto <bb 25>; [11.00%]

  <bb 21> [local count: 9299136]:
  _95 = s_8(D) + 7;
  _96 = *_95;
  p_9(D)->v[7] = _96;
  if (c_7(D) > 8)
    goto <bb 22>; [89.00%]
  else
    goto <bb 25>; [11.00%]

  <bb 22> [local count: 8276231]:
  _102 = s_8(D) + 8;
  _103 = *_102;
  p_9(D)->v[8] = _103;
  if (c_7(D) > 9)
    goto <bb 27>; [89.00%]
  else
    goto <bb 25>; [11.00%]

  <bb 27> [local count: 7365846]:

  <bb 23> [local count: 7365845]:
  # ivtmp.15_151 = PHI <9(27), ivtmp.15_150(29)>
  _26 = MEM[base: s_8(D), index: ivtmp.15_151, offset: 0B];
  MEM[base: p_9(D), index: ivtmp.15_151, offset: 0B] = _26;
  ivtmp.15_150 = ivtmp.15_151 + 1;
  i_149 = (int) ivtmp.15_150;
  if (c_7(D) > i_149)
    goto <bb 29>; [89.00%]
  else
    goto <bb 25>; [11.00%]

  <bb 29> [local count: 6555602]:
  goto <bb 23>; [100.00%]

  <bb 24> [local count: 84095460]:

  <bb 25> [local count: 105119324]:

  <bb 26> [local count: 118111600]:
  return;

}
Comment 1 Martin Sebor 2020-05-14 19:21:14 UTC
The missed-optimization keyword is for the unnecessary loop unrolling.
Comment 2 Martin Sebor 2020-05-14 19:24:26 UTC
See also pr92110 for a report of redundant -Wstringop-overflow instances due to loop unrolling.  A single warning should suffice (especially when it's a false positive).
Comment 3 Jakub Jelinek 2020-05-14 19:25:52 UTC
The warning should change, not the conservative assumption.  There is a lot of code in the wild with such trailing arrays, not everything uses flexible array members, [0] or [1] for that.
Comment 4 Martin Sebor 2020-05-14 20:30:58 UTC
No.  GCC's manual recommends using either flexible array members or zero-length arrays, and explicitly discourages abuses of arrays of length one (nothing is said about any such exceptions for larger arrays):

  Although using one-element arrays this way is discouraged, GCC handles accesses to trailing one-element array members analogously to zero-length arrays.

Legacy code that misuses arrays of larger bounds either needs to be updated to use the recommended solutions or it can suppress the warning using one of the provided mechanisms.  Otherwise, undefined code will be increasingly diagnosed (in line with the reporter's expectation).
Comment 5 Richard Biener 2020-07-23 06:51:49 UTC
GCC 10.2 is released, adjusting target milestone.
Comment 6 Martin Sebor 2021-02-10 20:28:51 UTC
The problem isn't specific to trailing arrays; it can be reproduced with an interior member as well:

$ gcc -O3 -S -Wall  pr95140.cpr95140.c: In function ‘f’:
pr95140.c:9:13: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
    9 |     p->v[i] = s[i];
      |     ~~~~~~~~^~~~~~
pr95140.c:3:8: note: at offset 8 into destination object ‘v’ of size 8
    3 |   char v[8], u;
      |        ^
...
pr95140.c:9:13: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
    9 |     p->v[i] = s[i];
      |     ~~~~~~~~^~~~~~
pr95140.c:3:8: note: at offset 14 into destination object ‘v’ of size 8
    3 |   char v[8], u;
      |        ^
Comment 7 Richard Biener 2021-04-08 12:02:30 UTC
GCC 10.3 is being released, retargeting bugs to GCC 10.4.
Comment 8 Andrew Pinski 2022-01-09 22:30:17 UTC
*** Bug 103956 has been marked as a duplicate of this bug. ***
Comment 9 Jakub Jelinek 2022-06-28 10:40:43 UTC
GCC 10.4 is being released, retargeting bugs to GCC 10.5.
Comment 10 Richard Biener 2023-07-07 10:37:27 UTC
GCC 10 branch is being closed.
Comment 11 Richard Biener 2024-07-19 13:07:52 UTC
GCC 11 branch is being closed.