Bug 92939 - missing -Wstringop-overflow on negative index from the end of array
Summary: missing -Wstringop-overflow on negative index from the end of array
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 10.0
: P3 normal
Target Milestone: 11.0
Assignee: Martin Sebor
URL:
Keywords: diagnostic
Depends on:
Blocks: Wstringop-overflow
  Show dependency treegraph
 
Reported: 2019-12-14 00:16 UTC by Martin Sebor
Modified: 2020-06-10 18:06 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work: 11.0
Known to fail: 10.1.0
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Sebor 2019-12-14 00:16:14 UTC
Even with -Wno-array-bounds the out-of-bounds stores in the first assignment to p[1] below and in the last assignment to p[-2] should be diagnosed by -Wstringop-overflow.  But only the first is because the implementation of the warning (the compute_objsize function) isn't prepared to handle negative offsets.

$ cat b.c && gcc -O2 -S -Wall -Wno-array-bounds b.c
void sink (void*);

void f (int n, int i)
{
  if (n < 2 || 3 < n) n = 2;
  if (i < 1 || 2 < i) i = 1;

  char a[3], *p = a + n;

               //     N=2              N=3
               // I=1     I=2      I=1     I=2
  p[1] = 0;    // a[3]    a[3]     a[4]    a[4]    << warns
  p[0] = 0;    // a[2]    a[2]     a[3]    a[3]    << should not warn
  p[-1] = 0;   // a[1]    a[1]     a[2]    a[2]    << must not warn
  p -= i;
  p[0]  = 0;   // a[1]    a[0]     a[2]    a[1]    << must not warn
  p[-1] = 0;   // a[0]    a[-1]    a[1]    a[0]    << should not warn
  p[-2] = 0;   // a[-1]   a[-2]    a[0]    a[-1]   << should not warn
  p -= i;
  p[0] = 0;    // a[0]    a[-1]    a[1]    a[0]    << should not warn
  p[-1] = 0;   // a[-1]   a[-2]    a[0]    a[-1]   << should not warn
  p[-2] = 0;   // a[-2]   a[-3]    a[-1]   a[-2]   << should warn

  sink (p);
}

b.c: In function ‘f’:
b.c:12:8: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   12 |   p[1] = 0;    // a[3]    a[3]     a[4]    a[4]    << warns
      |   ~~~~~^~~
b.c:8:8: note: at offset 0 to object ‘a’ with size 3 declared here
    8 |   char a[3], *p = a + n;
      |        ^


Without -Wno-array-bounds GCC correctly diagnoses the out-of-bounds access:

b.c: In function ‘f’:
b.c:12:4: warning: array subscript [3, 4] is outside array bounds of ‘char[3]’ [-Warray-bounds]
   12 |   p[1] = 0;    // a[3]    a[3]     a[4]    a[4]    << warns
      |   ~^~~
b.c:8:8: note: while referencing ‘a’
    8 |   char a[3], *p = a + n;
      |        ^
b.c:22:4: warning: array subscript [-4, -1] is outside array bounds of ‘char[3]’ [-Warray-bounds]
   22 |   p[-2] = 0;   // a[-2]   a[-3]    a[-1]   a[-2]   << should warn
      |   ~^~~~
b.c:8:8: note: while referencing ‘a’
    8 |   char a[3], *p = a + n;
      |        ^
Comment 1 GCC Commits 2020-06-10 18:02:25 UTC
The master branch has been updated by Martin Sebor <msebor@gcc.gnu.org>:

https://gcc.gnu.org/g:a2c2cee92e5defff9bf23d3b1184ee96e57e5fdd

commit r11-1183-ga2c2cee92e5defff9bf23d3b1184ee96e57e5fdd
Author: Martin Sebor <msebor@redhat.com>
Date:   Wed Jun 10 12:00:08 2020 -0600

    PR middle-end/95353 - spurious -Wstringop-overflow writing to a trailing array plus offset
    
    Also resolves:
    PR middle-end/92939 - missing -Wstringop-overflow on negative index from the end of array
    
    gcc/ChangeLog:
    
            PR middle-end/95353
            PR middle-end/92939
            * builtins.c (inform_access): New function.
            (check_access): Call it.  Add argument.
            (addr_decl_size): Remove.
            (get_range): New function.
            (compute_objsize): New overload.  Only use compute_builtin_object_size
            with raw memory function.
            (check_memop_access): Pass new argument to compute_objsize and
            check_access.
            (expand_builtin_memchr, expand_builtin_strcat): Same.
            (expand_builtin_strcpy, expand_builtin_stpcpy_1): Same.
            (expand_builtin_stpncpy, check_strncat_sizes): Same.
            (expand_builtin_strncat, expand_builtin_strncpy): Same.
            (expand_builtin_memcmp): Same.
            * builtins.h (check_nul_terminated_array): Declare extern.
            (check_access): Add argument.
            (struct access_ref, struct access_data): New structs.
            * gimple-ssa-warn-restrict.c (clamp_offset): New helper.
            (builtin_access::overlap): Call it.
            * tree-object-size.c (decl_init_size): Declare extern.
            (addr_object_size): Correct offset computation.
            * tree-object-size.h (decl_init_size): Declare.
            * tree-ssa-strlen.c (handle_integral_assign): Remove a call
            to maybe_warn_overflow when assigning to an SSA_NAME.
    
    gcc/testsuite/ChangeLog:
    
            PR middle-end/95353
            PR middle-end/92939
            * c-c++-common/Wstringop-truncation.c: Remove an xfail.
            * gcc.dg/Warray-bounds-46.c: Remove a bogus warning.
            * gcc.dg/Wrestrict-9.c: Disable -Wstringop-overflow.
            * gcc.dg/Wstringop-overflow-12.c: Remove xfails.
            * gcc.dg/Wstringop-overflow-28.c: Same.
            * gcc.dg/builtin-stringop-chk-4.c: Same.
            * gcc.dg/builtin-stringop-chk-5.c: Same.
            * gcc.dg/builtin-stringop-chk-8.c: Same.
            * gcc.dg/strlenopt-74.c: Avoid buffer overflow.
            * gcc.dg/Wstringop-overflow-34.c: New test.
            * gcc.dg/Wstringop-overflow-35.c: New test.
            * gcc.dg/Wstringop-overflow-36.c: New test.
            * gcc.dg/Wstringop-overflow-37.c: New test.
            * gcc.dg/Wstringop-overflow-38.c: New test.
Comment 2 Martin Sebor 2020-06-10 18:06:54 UTC
After r11-1183 GCC detects the overflow as expected:

$ gcc -O2 -S -Wall -Wextra -Wno-array-bounds pr92939.c

pr92939.c: In function ‘f’:
pr92939.c:12:8: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   12 |   p[1] = 0;    // a[3]    a[3]     a[4]    a[4]    << warns
      |   ~~~~~^~~
pr92939.c:8:8: note: at offset 3 to object ‘a’ with size 3 declared here
    8 |   char a[3], *p = a + n;
      |        ^
pr92939.c:22:9: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   22 |   p[-2] = 0;   // a[-2]   a[-3]    a[-1]   a[-2]   << should warn
      |   ~~~~~~^~~
pr92939.c:8:8: note: at offset -1 to object ‘a’ with size 3 declared here
    8 |   char a[3], *p = a + n;
      |        ^