https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83508
Martin Sebor <msebor at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Keywords| |diagnostic Status|UNCONFIRMED |ASSIGNED Last reconfirmed| |2017-12-20 Assignee|unassigned at gcc dot gnu.org |msebor at gcc dot gnu.org Ever confirmed|0 |1 --- Comment #1 from Martin Sebor <msebor at gcc dot gnu.org> --- Confirmed with an arm-linux-gnueabi cross-compiler and the test case below. Most (all?) back-ends transform the strcpy call into memcpy first (in the handle_builtin_strcpy function in tree-ssa-strlen.c), just after warning for the out-of-bounds offset. After transforming the call handle_builtin_strcpy also sets the no-warning bit on the new statement to prevent warning on it again. Most back-ends (or at least some, including x86_64) also transform the memcpy call into MEM_REF. The arm compiler, however, doesn't and leaves the invalid memcpy call alone. The invalid memcpy call is ultimately noticed by the -Wstringop-overflow checker which hasn't been updated to check the no-warning bit. That results in the duplicate warning. I think this points out not just (minor) issue with the warning but a more serious weakness in the buffer overflow detection and prevention (_FORTIFY_SOURCE) which lets this bug slip through. This is one of the downsides of allowing even invalid calls to be folded. $ cat a.c && gcc -O2 -S -Wall -fdump-tree-optimized=/dev/stdout a.c char* strcpy (char*, const char*); void sink (void*); void f (__PTRDIFF_TYPE__ i) { char a[8] = "012"; if (i < __PTRDIFF_MAX__ - 2 || __PTRDIFF_MAX__ - 1 < i) i = __PTRDIFF_MAX__ - 2; strcpy (a + i, a); sink (a); } a.c: In function ‘f’: a.c:12:3: warning: ‘strcpy’ offset [2147483645, 2147483646] is out of the bounds [0, 8] of object ‘a’ with type ‘char[8]’ [-Warray-bounds] strcpy (a + i, a); ^~~~~~~~~~~~~~~~~ a.c:7:8: note: ‘a’ declared here char a[8] = "012"; ^ ;; Function f (f, funcdef_no=0, decl_uid=4214, cgraph_uid=0, symbol_order=0) f (int i) { char a[8]; unsigned int i.0_1; unsigned int _2; char * _4; sizetype prephitmp_12; <bb 2> [local count: 1073741825]: a = "012"; i.0_1 = (unsigned int) i_8(D); _2 = i.0_1 + 2147483651; if (_2 > 1) goto <bb 3>; [64.00%] else goto <bb 4>; [36.00%] <bb 3> [local count: 687194769]: <bb 4> [local count: 1073741825]: # prephitmp_12 = PHI <i.0_1(2), 2147483645(3)> _4 = &a + prephitmp_12; __builtin_memcpy (_4, &a, 4); sink (&a); a ={v} {CLOBBER}; return; } a.c:12:3: warning: ‘__builtin_memcpy’ writing 4 bytes into a region of size 0 overflows the destination [-Wstringop-overflow=] strcpy (a + i, a); ^~~~~~~~~~~~~~~~~