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; }
The missed-optimization keyword is for the unnecessary loop unrolling.
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).
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.
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).
GCC 10.2 is released, adjusting target milestone.
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; | ^
GCC 10.3 is being released, retargeting bugs to GCC 10.4.
*** Bug 103956 has been marked as a duplicate of this bug. ***
GCC 10.4 is being released, retargeting bugs to GCC 10.5.
GCC 10 branch is being closed.
GCC 11 branch is being closed.