https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108036
Bug ID: 108036 Summary: Spurious warning for zero-sized array parameters to a function Product: gcc Version: 12.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: colomar.6.4.3 at gmail dot com Target Milestone: --- It's interesting to pass pointers to one past the end of an array to a function, acting as a sentinel value that serves as an alternative to the size of the buffer. It helps chaining string copy functions, for example: char * ustr2stpe(char *dst, const char *restrict src, size_t n, char past_end[0]) { bool trunc; char *end; ptrdiff_t len; if (dst == past_end) return past_end; trunc = false; len = strnlen(src, n); if (len > past_end - dst - 1) { len = past_end - dst - 1; trunc = true; } end = mempcpy(dst, src, len); *end = '\0'; return trunc ? past_end : end; } However, if you use array syntax for it, which clarifies where it points to, the GCC complains, not at the function implementation, but at call site: #define nitems(arr) (sizeof((arr)) / sizeof((arr)[0])) int main(void) { char pre[4] = "pre."; char *post = ".post"; char *src = "some-long-body.post"; char dest[100]; char *p, *past_end; past_end = dest + nitems(dest); p = dest; p = ustr2stpe(p, pre, nitems(pre), past_end); p = ustr2stpe(p, src, strlen(src) - strlen(post), past_end); p = ustr2stpe(p, "", 0, past_end); if (p == past_end) fprintf(stderr, "truncation\n"); puts(dest); // "pre.some-long-body" } $ cc -Wall -Wextra ustr2stpe.c ustr2stpe.c: In function ‘main’: ustr2stpe.c:43:13: warning: ‘ustr2stpe’ accessing 1 byte in a region of size 0 [-Wstringop-overflow=] 43 | p = ustr2stpe(p, pre, nitems(pre), past_end); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ustr2stpe.c:43:13: note: referencing argument 4 of type ‘char[0]’ ustr2stpe.c:10:1: note: in a call to function ‘ustr2stpe’ 10 | ustr2stpe(char *dst, const char *restrict src, size_t n, char past_end[0]) | ^~~~~~~~~ ustr2stpe.c:44:13: warning: ‘ustr2stpe’ accessing 1 byte in a region of size 0 [-Wstringop-overflow=] 44 | p = ustr2stpe(p, src, strlen(src) - strlen(post), past_end); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ustr2stpe.c:44:13: note: referencing argument 4 of type ‘char[0]’ ustr2stpe.c:10:1: note: in a call to function ‘ustr2stpe’ 10 | ustr2stpe(char *dst, const char *restrict src, size_t n, char past_end[0]) | ^~~~~~~~~ ustr2stpe.c:45:13: warning: ‘ustr2stpe’ accessing 1 byte in a region of size 0 [-Wstringop-overflow=] 45 | p = ustr2stpe(p, "", 0, past_end); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ustr2stpe.c:45:13: note: referencing argument 4 of type ‘char[0]’ ustr2stpe.c:10:1: note: in a call to function ‘ustr2stpe’ 10 | ustr2stpe(char *dst, const char *restrict src, size_t n, char past_end[0]) | ^~~~~~~~~ ustr2stpe.c:43:13: warning: ‘ustr2stpe’ accessing 1 byte in a region of size 0 [-Wstringop-overflow=] 43 | p = ustr2stpe(p, pre, nitems(pre), past_end); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ustr2stpe.c:43:13: note: referencing argument 4 of type ‘char[0]’ ustr2stpe.c:10:1: note: in a call to function ‘ustr2stpe’ 10 | ustr2stpe(char *dst, const char *restrict src, size_t n, char past_end[0]) | ^~~~~~~~~ ustr2stpe.c:44:13: warning: ‘ustr2stpe’ accessing 1 byte in a region of size 0 [-Wstringop-overflow=] 44 | p = ustr2stpe(p, src, strlen(src) - strlen(post), past_end); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ustr2stpe.c:44:13: note: referencing argument 4 of type ‘char[0]’ ustr2stpe.c:10:1: note: in a call to function ‘ustr2stpe’ 10 | ustr2stpe(char *dst, const char *restrict src, size_t n, char past_end[0]) | ^~~~~~~~~ ustr2stpe.c:45:13: warning: ‘ustr2stpe’ accessing 1 byte in a region of size 0 [-Wstringop-overflow=] 45 | p = ustr2stpe(p, "", 0, past_end); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ustr2stpe.c:45:13: note: referencing argument 4 of type ‘char[0]’ ustr2stpe.c:10:1: note: in a call to function ‘ustr2stpe’ 10 | ustr2stpe(char *dst, const char *restrict src, size_t n, char past_end[0]) | ^~~~~~~~~ The warnings are invalid. While it's true that I'm referencing a pointer of size 0, it's false that I'm "accessing 1 byte" in that region. I guess this is all about the bogus design of 'static' in ISO C, where you can have an array parameter of size 0, which is very useful in cases like this one. See the original report in the mailing list, where Richard Biener had some guess of what might be the reason: <https://gcc.gnu.org/pipermail/gcc/2022-December/240230.html>