https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88921
Bug ID: 88921 Summary: inconsistent warning on a power-of-2 memcpy with out-of-bounds offset Product: gcc Version: 9.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: --- None of the obviously invalid calls to memcpy in the test case below is diagnosed on common targets that fold memcpy calls with small power-of-2 sizes into MEM_REF. They are, however, diagnosed on targets like arm-eabi that don't fold such calls. This not makes writing tests for these kinds of warnings tedious (they may pass or fail on common targets used for development only to fail on secondary targets), it also makes developing portable software difficult when it compiles cleanly during development but fails on targets for which builds are done only rarely (usually because of scarcity of target boards). GCC should issue warnings for invalid constructs consistently and regardless of the target. $ cat t.c && gcc -O2 -S -Wall -Wextra -fdump-tree-wrestrict=/dev/stdout t.c extern char a[]; void f (const char *s, __SIZE_TYPE__ i) { i = __PTRDIFF_MAX__ - 1; __builtin_memcpy (a + i, s, 2); } void g (const char *s, __PTRDIFF_TYPE__ i) { i = __PTRDIFF_MAX__ - 1; __builtin_memcpy (a + i, s, 2); } void h (const char *s, __PTRDIFF_TYPE__ i) { if (i < __PTRDIFF_MAX__ - 1) i = __PTRDIFF_MAX__ - 1; __builtin_memcpy (a + i, s, 2); } ;; Function f (f, funcdef_no=0, decl_uid=1908, cgraph_uid=1, symbol_order=0) f (const char * s, long unsigned int i) { short unsigned int _3; <bb 2> [local count: 1073741824]: _3 = MEM[(char * {ref-all})s_2(D)]; MEM[(char * {ref-all})&a + 9223372036854775806B] = _3; return; } ;; Function g (g, funcdef_no=1, decl_uid=1912, cgraph_uid=2, symbol_order=1) g (const char * s, long int i) { short unsigned int _3; <bb 2> [local count: 1073741824]: _3 = MEM[(char * {ref-all})s_2(D)]; MEM[(char * {ref-all})&a + 9223372036854775806B] = _3; return; } ;; Function h (h, funcdef_no=2, decl_uid=1916, cgraph_uid=3, symbol_order=2) h (const char * s, long int i) { sizetype i.1_1; void * _2; short unsigned int _7; <bb 2> [local count: 1073741824]: i_4 = MAX_EXPR <i_3(D), 9223372036854775806>; i.1_1 = (sizetype) i_4; _2 = &a + i.1_1; _7 = MEM[(char * {ref-all})s_6(D)]; MEM[(char * {ref-all})_2] = _7; return; } Contrast that to: $ /build/arm-none-eabi/gcc-svn/gcc/xgcc -B /build/arm-none-eabi/gcc-svn/gcc -O2 -S -Wall -Wextra -fdump-tree-wrestrict=/dev/stdout t.c ;; Function f (f, funcdef_no=0, decl_uid=4141, cgraph_uid=1, symbol_order=0) t.c: In function ‘f’: t.c:7:3: warning: ‘__builtin_memcpy’ pointer overflow between offset 2147483646 and size 2 accessing array ‘a’ with type ‘char[]’ [-Warray-bounds] 7 | __builtin_memcpy (a + i, s, 2); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ t.c:1:13: note: array ‘a’ declared here 1 | extern char a[]; | ^ f (const char * s, unsigned int i) { <bb 2> [local count: 1073741824]: __builtin_memcpy (&MEM[(void *)&a + 2147483646B], s_2(D), 2); return; } ;; Function g (g, funcdef_no=1, decl_uid=4145, cgraph_uid=2, symbol_order=1) t.c: In function ‘g’: t.c:14:3: warning: ‘__builtin_memcpy’ pointer overflow between offset 2147483646 and size 2 accessing array ‘a’ with type ‘char[]’ [-Warray-bounds] 14 | __builtin_memcpy (a + i, s, 2); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ t.c:1:13: note: array ‘a’ declared here 1 | extern char a[]; | ^ g (const char * s, int i) { <bb 2> [local count: 1073741824]: __builtin_memcpy (&MEM[(void *)&a + 2147483646B], s_2(D), 2); return; } ;; Function h (h, funcdef_no=2, decl_uid=4149, cgraph_uid=3, symbol_order=2) t.c: In function ‘h’: t.c:22:3: warning: ‘__builtin_memcpy’ pointer overflow between offset [2147483646, 2147483647] and size 2 accessing array ‘a’ with type ‘char[]’ [-Warray-bounds] 22 | __builtin_memcpy (a + i, s, 2); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ t.c:1:13: note: array ‘a’ declared here 1 | extern char a[]; | ^ h (const char * s, int i) { sizetype i.1_1; void * _2; <bb 2> [local count: 1073741824]: i_4 = MAX_EXPR <i_3(D), 2147483646>; i.1_1 = (sizetype) i_4; _2 = &a + i.1_1; __builtin_memcpy (_2, s_6(D), 2); return; }