The combination of signed and unsigned offsets into an array of elements larger than 1 triggers a false positive -Wstringop-overflow. $ cat q.c && gcc -O2 -S q.c void sink (void*, ...); void f (unsigned i, int j) { i |= 1; // [1, UINT_MAX] j |= 1; // [INT_MIN + 1, -1] U [1, INT_MAX] int a[5]; // index int *p1 = a + i; // 1-5 int *p2 = p1 + j; // 0-5 __builtin_memset (p2, 0, 5 * sizeof *a); sink (p1, p2); } q.c: In function ‘f’: q.c:12:3: warning: ‘__builtin_memset’ writing 20 bytes into a region of size 16 overflows the destination [-Wstringop-overflow=] 12 | __builtin_memset (p2, 0, 5 * sizeof *a); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ q.c:8:7: note: at offset [4, 17179869176] into destination object ‘a’ 8 | int a[5]; // index | ^ The optimized dump below suggests the "anti-range" the signed offset is in isn't being handled correctly. f (unsigned intD.9 iD.1932, intD.6 jD.1933) { unsigned intD.9 i_5(D) = iD.1932; intD.6 j_7(D) = jD.1933; intD.6 * p2D.1938; intD.6 * p1D.1937; intD.6 aD.1936[5]; long unsigned intD.10 _1; long unsigned intD.10 _2; long unsigned intD.10 _3; long unsigned intD.10 _4; ;; basic block 2, loop depth 0, count 1073741824 (estimated locally), maybe hot ;; prev block 0, next block 1, flags: (NEW, REACHABLE, VISITED) ;; pred: ENTRY [always] count:1073741824 (estimated locally) (FALLTHRU,EXECUTABLE) # RANGE [1, 4294967295] i_6 = i_5(D) | 1; # RANGE [-2147483647, 2147483647] j_8 = j_7(D) | 1; # RANGE [1, 4294967295] NONZERO 4294967295 _1 = (long unsigned intD.10) i_6; # RANGE [4, 17179869180] NONZERO 17179869180 _2 = _1 * 4; # PT = { D.1936 } (escaped) # ALIGN = 4, MISALIGN = 0 p1_9 = &aD.1936 + _2; # RANGE ~[2147483648, 18446744071562067968] _3 = (long unsigned intD.10) j_8; # RANGE [0, 18446744073709551612] NONZERO 18446744073709551612 _4 = _3 * 4; # PT = { D.1936 } (escaped) # ALIGN = 4, MISALIGN = 0 p2_10 = p1_9 + _4; # .MEM_12 = VDEF <.MEM_11(D)> # USE = nonlocal null { D.1936 } (escaped) # CLB = nonlocal null { D.1936 } (escaped) memsetD.894 (p2_10, 0, 20);
Patch: https://gcc.gnu.org/pipermail/gcc-patches/2020-October/555946.html
The master branch has been updated by Martin Sebor <msebor@gcc.gnu.org>: https://gcc.gnu.org/g:83685efd5fd1623cfc4e4c435ce2773d95d458d1 commit r11-3827-g83685efd5fd1623cfc4e4c435ce2773d95d458d1 Author: Martin Sebor <msebor@redhat.com> Date: Fri Oct 9 14:48:43 2020 -0600 Generalize compute_objsize to return maximum size/offset instead of failing (PR middle-end/97023). Also resolves: PR middle-end/97342 - bogus -Wstringop-overflow with nonzero signed and unsigned offsets PR middle-end/97023 - missing warning on buffer overflow in chained mempcpy PR middle-end/96384 - bogus -Wstringop-overflow= storing into multidimensional array with index in range gcc/ChangeLog: PR middle-end/97342 PR middle-end/97023 PR middle-end/96384 * builtins.c (access_ref::access_ref): Initialize new member. Use new enum. (access_ref::size_remaining): Define new member function. (inform_access): Handle expressions referencing objects. (gimple_call_alloc_size): Call get_size_range instead of get_range. (gimple_call_return_array): New function. (get_range): Rename... (get_offset_range): ...to this. Improve detection of ranges from types of expressions. (gimple_call_return_array): Adjust calls to get_range per above. (compute_objsize): Same. Set maximum size or offset instead of failing for unknown objects and handle more kinds of expressions. (compute_objsize): Call access_ref::size_remaining. (compute_objsize): Have transitional wrapper fail for pointers into unknown objects. (expand_builtin_strncmp): Call access_ref::size_remaining and handle new cases. * builtins.h (access_ref::size_remaining): Declare new member function. (access_ref::set_max_size_range): Define new member function. (access_ref::add_ofset, access_ref::add_max_ofset): Same. (access_ref::add_base0): New data member. * calls.c (get_size_range): Change argument type. Handle new condition. * calls.h (get_size_range): Adjust signature. (enum size_range_flags): Define new type. * gimple-ssa-warn-restrict.c (builtin_memref::builtin_memref): Correct argument to get_size_range. * tree-ssa-strlen.c (get_range): Handle anti-ranges. (maybe_warn_overflow): Check DECL_P before assuming it's one. gcc/testsuite/ChangeLog: PR middle-end/97342 PR middle-end/97023 PR middle-end/96384 * c-c++-common/Wrestrict.c: Adjust comment. * gcc.dg/Wstringop-overflow-34.c: Remove xfail. * gcc.dg/Wstringop-overflow-43.c: Remove xfails. Adjust regex patterns. * gcc.dg/pr51683.c: Prune out expected warning. * gcc.target/i386/pr60693.c: Same. * g++.dg/warn/Wplacement-new-size-8.C: New test. * gcc.dg/Wstringop-overflow-41.c: New test. * gcc.dg/Wstringop-overflow-44.s: New test. * gcc.dg/Wstringop-overflow-45.c: New test. * gcc.dg/Wstringop-overflow-46.c: New test. * gcc.dg/Wstringop-overflow-47.c: New test. * gcc.dg/Wstringop-overflow-49.c: New test. * gcc.dg/Wstringop-overflow-50.c: New test. * gcc.dg/Wstringop-overflow-51.c: New test. * gcc.dg/Wstringop-overflow-52.c: New test. * gcc.dg/Wstringop-overflow-53.c: New test. * gcc.dg/Wstringop-overflow-54.c: New test. * gcc.dg/Wstringop-overflow-55.c: New test. * gcc.dg/Wstringop-overread-5.c: New test.
Fixed in r11-3827.