Bug 105438 - [12/13/14/15 Regression] Incorrect array-bounds warning with array size carried over from a previous template instantiation since r11-4987-g602c6cfc79ce4ae6
Summary: [12/13/14/15 Regression] Incorrect array-bounds warning with array size carri...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: ipa (show other bugs)
Version: 13.1.1
: P2 normal
Target Milestone: 13.4
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks: Warray-bounds
  Show dependency treegraph
 
Reported: 2022-04-30 08:24 UTC by Bernie Innocenti
Modified: 2024-07-19 12:45 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2022-05-02 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Bernie Innocenti 2022-04-30 08:24:55 UTC
Minified testcase (almost every line is necessary to reproduce):

```
/* g++ -Warray-bounds -O2 repro.cc */

int longer[7] = {};
int shorter[2] = {};
int out[10] = {};

template <int N>
void configure(const int(&in)[N], const int nrows = N)
{
    if (nrows <= 10)
    {
        for (int i = 0; i < nrows; i++)
        {
            out[i] = in[i];
        }
    }
}

int main()
{
  configure(longer);
  configure(shorter);
}
```

Output:

```
$ g++ -Warray-bounds -O2 repro.cc
repro.cc: In function 'int main()':
repro.cc:13:24: warning: array subscript 'const int [7][0]' is partly outside array bounds of 'int [2]' [-Warray-bounds]
   13 |             out[i] = in[i];
      |                      ~~^
repro.cc:3:5: note: while referencing 'shorter'
    3 | int shorter[2] = {};
      |     ^~~~~~~
repro.cc:13:24: warning: array subscript 'const int [7][0]' is partly outside array bounds of 'int [2]' [-Warray-bounds]
   13 |             out[i] = in[i];
      |                      ~~^
repro.cc:3:5: note: while referencing 'shorter'
    3 | int shorter[2] = {};
      |     ^~~~~~~
```

Static analysis appears to be using the length of the longer array for the call using the shorter array.

The warning disappears by:
 * commenting out the first call to configure() suppresses the warning
 * swapping the two calls to configure()
 * commenting out if statement also eliminates the warning
 * making longer and shorter the same size
 * using N as loop counter instead of nrows
Comment 1 Bernie Innocenti 2022-04-30 08:27:12 UTC
Reproducible in Godbolt with any 11.x release as well as trunk:
https://godbolt.org/z/zWb55P8G7
Comment 2 Bernie Innocenti 2022-05-02 06:05:44 UTC
GCC 12.0.1 20220413 (Red Hat 12.0.1-0) gives a more helpful diagnostic with inlining backtrace:

In function ‘void configure(const int (&)[N], int) [with int N = 7]’,
    inlined from ‘void configure(const int (&)[N], int) [with int N = 2]’ at testcase.cc:8:6,
    inlined from ‘int main()’ at gcc-array-bounds-bug-testcase.cc:22:12:
testcase.cc:14:24: warning: array subscript ‘const int [7][0]’ is partly outside array bounds of ‘int [2]’ [-Warray-bounds]
   14 |             out[i] = in[i];
      |                      ~~^


Note how configure<N=7>() was inlined into configure<N=7>().
Comment 3 Bernie Innocenti 2022-05-02 06:07:08 UTC
Not sure if this is helpful, but the IPA dump also shows two calls to configure() with N=7 and none with N=2:

IPA function summary for int main()/3 inlinable
  global time:     26.000000
  self size:       9
  global size:     9
  min size:       6
  self stack:      0
  global stack:    0
    size:0.000000, time:0.000000
    size:3.000000, time:2.000000,  executed if:(not inlined)
  calls:
    void configure(const int (&)[N], int) [with int N = 7]/6 function not considered for inlining
      freq:1.00 loop depth: 0 size: 3 time: 12 callee size: 5 stack: 0
       op0 is compile time invariant
       op1 is compile time invariant
    void configure(const int (&)[N], int) [with int N = 7]/6 function not considered for inlining
      freq:1.00 loop depth: 0 size: 3 time: 12 callee size: 5 stack: 0
       op0 is compile time invariant
       op1 is compile time invariant
Comment 4 Bernie Innocenti 2022-05-02 06:11:42 UTC
Furthermore, after the inline pass main() has a reference to the shorter array with an annotation of int[7], which is clearly wrong:

  <bb 5> [local count: 939524097]:
  _5 = MEM[(const int[7] &)&shorter][i_4];
  out[i_4] = _5;
  i_6 = i_4 + 1;
Comment 5 Richard Biener 2022-05-02 06:54:44 UTC
It's IPA ICF that merges the two functions.  We then end up inlining but not using the original function body but the merged one.
Comment 6 Andrew Pinski 2022-05-02 06:57:49 UTC
(In reply to Richard Biener from comment #5)
> It's IPA ICF that merges the two functions.  We then end up inlining but not
> using the original function body but the merged one.

I wonder if we could get wrong code because of that ...
Comment 7 Martin Liška 2022-05-03 12:27:31 UTC
Btw. started with r11-4987-g602c6cfc79ce4ae6.
Comment 8 Martin Liška 2022-05-03 12:42:54 UTC
So the 2 following functions are merged:

void _Z9configureILi7EEvRAT__Kii.part.0<7> (const int[7] & in, const int nrows)
{
...

void _Z9configureILi2EEvRAT__Kii.part.0<2> (const int[2] & in, const int nrows)
{
...

which have a different argument in. However I don't think one can't end with a wrong code as nrows argument would be different in:

  _Z9configureILi7EEvRAT__Kii.part.0<7> (&longer, 7);
  _Z9configureILi2EEvRAT__Kii.part.0<2> (&shorter, 2);

I was unable to come up with a code that would be miscompiled.
Comment 9 Richard Biener 2022-07-26 11:39:14 UTC
Sth should be done about the argument type mismatch though - like changing it to a "common" type (with open bound?)
Comment 10 Bernie Innocenti 2023-01-22 00:55:49 UTC
Still present on GCC 12.2.

Could someone look into it please, or point me at the point in ipa-icf.cc where the array-bounds analysis information should have been updated after merging the template instantiations?
Comment 11 Martin Liška 2023-02-09 11:37:31 UTC
(In reply to Bernie Innocenti from comment #10)
> Still present on GCC 12.2.
> 
> Could someone look into it please, or point me at the point in ipa-icf.cc
> where the array-bounds analysis information should have been updated after
> merging the template instantiations?

Well, you will need to modify all parameters and local variables at the end of
sem_function::merge function.
Comment 12 Jakub Jelinek 2023-05-29 10:06:57 UTC
GCC 11.4 is being released, retargeting bugs to GCC 11.5.
Comment 13 Bernie Innocenti 2023-07-20 07:23:48 UTC
Still present on g++ 13.1.1

I discovered that -O2 is required to trigger this bug. These compile without warnings:

 g++ -O1 -Warray-bounds repro.cc
 g++ -O3 -Warray-bounds repro.cc
 g++ -Ofast -Warray-bounds repro.cc
Comment 14 Richard Biener 2023-07-27 09:22:56 UTC
GCC 13.2 is being released, retargeting bugs to GCC 13.3.
Comment 15 Jakub Jelinek 2024-05-21 09:11:19 UTC
GCC 13.3 is being released, retargeting bugs to GCC 13.4.