Isolated from code passing a pointer into an array and the length of the array as separate arguments, where each function has the minimum length of the array encoded in its parameter declaration, and uses runtime conditionals to guarantee the minimum is met: // bar(p, n) may access p[0], p[1], ..., p[n-1], and requires n >= 128 void bar(unsigned char[static 128], unsigned); // foo(p, n) may access p[0], p[1], ..., p[n-1], and requires n >= 16 void foo(unsigned char p[static 16], unsigned n) { if (n % 128) n -= n % 128; if (n) bar(p, n); } <source>: In function 'foo': <source>:12:17: error: 'bar' accessing 128 bytes in a region of size 16 [-Werror=stringop-overflow=] 12 | bar(p, n); | ^~~~~~~~~ <source>:12:17: note: referencing argument 1 of type 'unsigned char[128]' <source>:2:6: note: in a call to function 'bar' 2 | void bar(unsigned char[static 128], unsigned n); | ^~~ cc1: all warnings being treated as errors Compiler returned: 1 Reproduced in GCC 10.5, 11.4, and 12.3. Not reproduced in any earlier versions of GCC. Using `if (n >= 128)' doesn't change anything, presumably because GCC doesn't know the connection between p and n.
There is another bug report dealing with this. But IIRC this is an expected warning as foo is being passed an array which is size 16 but then passed to bar as size 128 which would be undefined.
This is basically a dup of bug 108154 I think.
(In reply to Andrew Pinski from comment #1) > There is another bug report dealing with this. But IIRC this is an expected > warning as foo is being passed an array which is size 16 but then passed to > bar as size 128 which would be undefined. There is nothing undefined here. The caller's requirement as noted in the comment (which is not formally expressible in C, as far as I know, but is obviously extremely widespread practice) is that for foo(p, n) or bar(p, n), p must point to the first element of an array of at least n elements. foo additionally imposes the requirement that p have at least 16 elements. bar additionally imposes the requirement that p have at least 128 elements. When the caller meets foo's contract, foo meets bar's contract. So there is nothing undefined. From C11, Sec. 6.7.6.3 `Function declarators (including prototypes)', paragraph 7, p. 133: > A declaration of a parameter as ``array of type'' shall be adjusted > to ``qualified pointer to type'', where the type qualifiers (if any) > are those specified within the [ and ] of the array type derivation. > If the keyword static also appears within the [ and ] of the array > type derivation, then for each call to the function, the value of the > corresponding actual argument shall provide access to the first > element of an array with at least as many elements as specified by > the size expression. Here, as required, the value of the corresponding actual argument does provide access to the first element of an array with at least as many elements as specified by the size expression. In other words, this states a requirement about run-time values, which the code meets, not about compile-time parameter declarations, which is what GCC appears to object to. (In reply to Andrew Pinski from comment #2) > This is basically a dup of bug 108154 I think. That one appears to be different: it trips -Wstringop-overread, not -Wstringop-overflow.
(In reply to Taylor R Campbell from comment #3) > (In reply to Andrew Pinski from comment #2) > > This is basically a dup of bug 108154 I think. > > That one appears to be different: it trips -Wstringop-overread, not > -Wstringop-overflow. The infrastructure for both are the same for this static array parameters though. So ....
It is true that there is no UB, but the warning is not directly related to whether something is UB or not. It simply assumes that 16 is an upper bound although the standard does require this.