Bug 94195 - missing warning reading a smaller object via an lvalue of a larger type
Summary: missing warning reading a smaller object via an lvalue of a larger type
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: Warray-bounds
  Show dependency treegraph
 
Reported: 2020-03-16 15:27 UTC by Martin Sebor
Modified: 2020-09-27 20:25 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 10.2.0, 11.0, 8.4.0, 9.3.0
Last reconfirmed: 2020-08-07 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Sebor 2020-03-16 15:27:50 UTC
The following test case was derived from PR 94187.  The past-the-end store in f() is diagnosed by -Wstringop-overflow as expected but the corresponding past-the-end read in g() is not.  It's checked by -Warray-bounds but the code there doesn't fully consider the type of the access.

$ cat pr94187.c && gcc -O2 -S -Wall -Wextra -Wpedantic -fdump-tree-vrp=/dev/stdout pr94187.c
char a[1];

void f (void)
{
  *(int*)a = 0;      // -Wstringop-overflow (good)
}

int g (void)
{
  return *(int*)a;   // missing warning (-Warray-bounds)
}

;; Function f (f, funcdef_no=0, decl_uid=1931, cgraph_uid=1, symbol_order=1)

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2
;; 2 succs { 1 }

Value ranges after VRP:



f ()
{
  <bb 2> [local count: 1073741824]:
  MEM[(int *)&a] = 0;
  return;

}


pr94187.c: In function ‘f’:
pr94187.c:5:12: warning: writing 4 bytes into a region of size 1 [-Wstringop-overflow=]
    5 |   *(int*)a = 0;      // -Wstringop-overflow (good)
      |   ~~~~~~~~~^~~
pr94187.c:1:6: note: at offset 0 to object ‘a’ with size 1 declared here
    1 | char a[1];
      |      ^

;; Function f (f, funcdef_no=0, decl_uid=1931, cgraph_uid=1, symbol_order=1)

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2
;; 2 succs { 1 }

Value ranges after VRP:



f ()
{
  <bb 2> [local count: 1073741824]:
  MEM[(int *)&a] = 0;
  return;

}



;; Function g (g, funcdef_no=1, decl_uid=1934, cgraph_uid=2, symbol_order=2)

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2
;; 2 succs { 1 }

Value ranges after VRP:

_2: int VARYING


g ()
{
  int _2;

  <bb 2> [local count: 1073741824]:
  _2 = MEM[(int *)&a];
  return _2;

}



;; Function g (g, funcdef_no=1, decl_uid=1934, cgraph_uid=2, symbol_order=2)

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2
;; 2 succs { 1 }

Value ranges after VRP:

_2: int VARYING


g ()
{
  int _2;

  <bb 2> [local count: 1073741824]:
  _2 = MEM[(int *)&a];
  return _2;

}
Comment 1 Martin Sebor 2020-08-07 15:34:28 UTC
My patch for pr50584 includes code to handle this case as well.
Comment 2 CVS Commits 2020-09-19 23:57:40 UTC
The master branch has been updated by Martin Sebor <msebor@gcc.gnu.org>:

https://gcc.gnu.org/g:3f9a497d1b0dd9da87908a11b59bf364ad40ddca

commit r11-3306-g3f9a497d1b0dd9da87908a11b59bf364ad40ddca
Author: Martin Sebor <msebor@redhat.com>
Date:   Sat Sep 19 17:47:29 2020 -0600

    Extend -Warray-bounds to detect out-of-bounds accesses to array parameters.
    
    gcc/ChangeLog:
    
            PR middle-end/82608
            PR middle-end/94195
            PR c/50584
            PR middle-end/84051
            * gimple-array-bounds.cc (get_base_decl): New function.
            (get_ref_size): New function.
            (trailing_array): New function.
            (array_bounds_checker::check_array_ref): Call them.  Handle arrays
            declared in function parameters.
            (array_bounds_checker::check_mem_ref):  Same.  Handle references to
            dynamically allocated arrays.
    
    gcc/testsuite/ChangeLog:
    
            PR middle-end/82608
            PR middle-end/94195
            PR c/50584
            PR middle-end/84051
            * c-c++-common/Warray-bounds.c: Adjust.
            * gcc.dg/Wbuiltin-declaration-mismatch-9.c: Adjust.
            * gcc.dg/Warray-bounds-63.c: New test.
            * gcc.dg/Warray-bounds-64.c: New test.
            * gcc.dg/Warray-bounds-65.c: New test.
            * gcc.dg/Warray-bounds-66.c: New test.
            * gcc.dg/Warray-bounds-67.c: New test.
Comment 3 Dmitry G. Dyachenko 2020-09-26 18:10:28 UTC
(In reply to CVS Commits from comment #2)
> The master branch has been updated by Martin Sebor <msebor@gcc.gnu.org>:
> 
> https://gcc.gnu.org/g:3f9a497d1b0dd9da87908a11b59bf364ad40ddca
> 
> commit r11-3306-g3f9a497d1b0dd9da87908a11b59bf364ad40ddca
> Author: Martin Sebor <msebor@redhat.com>
> Date:   Sat Sep 19 17:47:29 2020 -0600
> 
>     Extend -Warray-bounds to detect out-of-bounds accesses to array
> parameters.
>     
>     gcc/ChangeLog:
>     
>             PR middle-end/82608
>             PR middle-end/94195
>             PR c/50584
>             PR middle-end/84051
>             * gimple-array-bounds.cc (get_base_decl): New function.
>             (get_ref_size): New function.
>             (trailing_array): New function.
>             (array_bounds_checker::check_array_ref): Call them.  Handle
> arrays
>             declared in function parameters.
>             (array_bounds_checker::check_mem_ref):  Same.  Handle references
> to
>             dynamically allocated arrays.
>     
>     gcc/testsuite/ChangeLog:
>     
>             PR middle-end/82608
>             PR middle-end/94195
>             PR c/50584
>             PR middle-end/84051
>             * c-c++-common/Warray-bounds.c: Adjust.
>             * gcc.dg/Wbuiltin-declaration-mismatch-9.c: Adjust.
>             * gcc.dg/Warray-bounds-63.c: New test.
>             * gcc.dg/Warray-bounds-64.c: New test.
>             * gcc.dg/Warray-bounds-65.c: New test.
>             * gcc.dg/Warray-bounds-66.c: New test.
>             * gcc.dg/Warray-bounds-67.c: New test.

I am a bit confused -- now gcc produces warning.
But access is not out of allocated memory.
Is it expected?


$ cat x.c
#include <stdlib.h>

struct S1 {
  unsigned x;
};
struct S {
  struct S1 s1;
  int z;
};

void f1()
{
  struct S *pS = (struct S*) calloc(sizeof(struct S1),1);
  if(pS->s1.x == 0)
    return;
  free(pS);
}

$ gcc -O2 -Wall -c x.i
x.c: In function 'f1':
x.c:18:8: warning: array subscript 'struct S[0]' is partly outside array bounds of 'unsigned char[4]' [-Warray-bounds]
   18 |   if(pS->s1.x == 0)
      |        ^~
x.c:17:30: note: referencing an object of size 4 allocated by 'calloc'
   17 |   struct S *pS = (struct S*) calloc(sizeof(struct S1),1);
      |                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~
Comment 4 Martin Sebor 2020-09-27 20:24:51 UTC
(In reply to Dmitry G. Dyachenko from comment #3)

The warning is expected.  The access to pS->s1.x implies that there must be an object at pS that's at least sizeof *pS large, even though only the leading 4 bytes of it are being accessed.
Comment 5 Martin Sebor 2020-09-27 20:25:31 UTC
Implemented for GCC 11 in r11-3306.