Search code examples
c++gccgcc-warning

Is this out-of-bounds warning from gcc erroneous?


Earlier today, gcc gave me a warning that I belive to be erroneous and now I am very unsure if it is an actual compiler bug(usually highly unlikely) or a bug in my code(usually highly likely). I managed to reduce it down to the following code:

#include <algorithm>
#include <array>
#include <iostream>

int main()
{
    std::array<int,8> test{};
    int valid = 0;
    for(int i=0;i<8;++i)
    {
        if(i==0)
            test[valid++] = 0;
    }
    
//    if(valid<8)
        std::sort(test.begin(),test.begin()+valid);
}

Here it is on Compiler explorer

When compiled with optimization level -O2 or higher with gcc 12.1 or trunk, this warning about an out-of-bounds access is emitted:

In file included from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/algorithm:61,
                 from <source>:1:
In function 'void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = int*; _Compare = __gnu_cxx::__ops::_Iter_less_iter]',
    inlined from 'void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = int*; _Compare = __gnu_cxx::__ops::_Iter_less_iter]' at /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/stl_algo.h:1844:5,
    inlined from 'void std::__sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = int*; _Compare = __gnu_cxx::__ops::_Iter_less_iter]' at /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/stl_algo.h:1940:31,
    inlined from 'void std::__sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = int*; _Compare = __gnu_cxx::__ops::_Iter_less_iter]' at /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/stl_algo.h:1932:5,
    inlined from 'void std::sort(_RAIter, _RAIter) [with _RAIter = int*]' at /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/stl_algo.h:4820:18,
    inlined from 'int main()' at <source>:16:15:
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/stl_algo.h:1849:32: error: array subscript 16 is outside array bounds of 'std::array<int, 8> [1]' [-Werror=array-bounds]
 1849 |           std::__insertion_sort(__first, __first + int(_S_threshold), __comp);
      |           ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>: In function 'int main()':
<source>:7:27: note: at offset 64 into object 'test' of size 32
    7 |         std::array<int,8> test{};

I believe that to be mistaken. According to my limited understanding, valid is only incremented once and will always be 1.

Even if the condition were replaced with some unpredictable function call, in the worst case it would be true every time, yielding valid==8 at the end of the loop, which should still be alright?

Additionally, I have thus far made the following observations:

  • The warning is not produced at lower optimization levels, on gcc <=11 or on clang.
  • Interestingly, the warning is also not produce with array sizes >8 or <6, only for sizes 6,7, and 8.
  • When I remove the condition inside the loop body(the "if(i==0)", to increment every time and always yield valid==8), the warning disappears.
  • When I add the condition before the sort call(and thereby provide the compiler with an additional hint about the limits of valid), the warning disappears.

Especially the latter two make me believe I might have managed to confuse gcc's analysis somehow, but also make me question if I am overlooking something obvious or managed to introduce some subtle undefined behaviour in my code.

Am I misunderstanding something in my sleep deprived state or did I encounter a genuine, mostly harmless, compiler bug?


Solution

  • It is indeed a compiler bug, as can be seen in this bugzilla report, which contains almost identical code to the one in my question.

    Thanks to Marc Glisse for providing this link to a lot of similar bugs and thereby helping me track down the relevant one.