In the following code:
#include <cstring>
template <unsigned len>
struct CharArray {
CharArray() {
memset(data_, 0, len);
}
char data_[len];
};
struct Foobar {
CharArray<5> a;
CharArray<3> b;
CharArray<0> c;
};
int main() {
Foobar f;
}
The type CharArray<0> ends up having a zero-sized array as its only member. I'm aware of this being a GCC extension and unsafe practice in general. The question is not about that.
When I compile the code with gcc 10.2.0, I get the following warning:
<source>: In function 'int main()':
<source>:5:3: warning: array subscript 8 is outside array bounds of 'Foobar [1]' [-Warray-bounds]
5 | CharArray() {
| ^~~~~~~~~
<source>:18:10: note: while referencing 'f'
18 | Foobar f;
| ^
With gcc9 and earlier there's no warning.
Question: Where does the subscript 8 come from? And what is the Foobar [1] mentioned there? It looks like there's an array of one Foobars and we're trying to access element 8 in that array. Not sure how that could happen. If somebody knows the details, I'd appreciate it if you could explain it.
This happens when compiling with gcc++-10 in Ubuntu 20.04 with -O3 -Wall -Wextra as options. If I don't pass any optimization flag, there won't be any warning. Also: if I take the constructor away, the warning will also disappear.
It seems the issue is somehow related to the
memset(): as avoiding it using a condition (len != 0) doesn't work it seems the compiler recognizes that the start address ofCharArray<0>'s object is produced by the intialization ofCharArray<3>and warns about that. This theory can be tested by conditionally not initializingCharArray<3>withmemset()or specializing that type as that makes the warning go way:or
The warning is probably spurious. It seems by the time the address of the zero sized array is used the compiler has "forgotten" that it was produced by accessing a different array's member. The easiest approach to avoid the warning seems to correctly initialize the
datain the initializer list and not usingmemset()at all: