I can reproduce it with both of these: $ gcc-13 --version | head -n1 gcc-13 (Debian 13.2.0-13) 13.2.0 $ gcc-14 --version | head -n1 gcc-14 (Debian 14-20240201-3) 14.0.1 20240131 (experimental) [master r14-8680-g2f14c0dbb78] See a small reproducer: ```c #include <err.h> #include <stddef.h> #include <stdlib.h> static const char **add_string(size_t *restrict n, const char *strings[restrict *n], const char *restrict string); int main(int argc, char *argv[argc + 1]) { size_t n = 0; const char **strings = NULL; add_string(&n, strings, argv[0]); } static const char ** add_string(size_t *restrict n, const char *strings[restrict *n], const char *restrict string) { strings = reallocarray(strings, ++*n, sizeof(const char *)); if (strings == NULL) err(EXIT_FAILURE, "reallocarray(3)"); strings[*n - 1] = string; return strings; } ``` alx@debian:~/tmp$ gcc-13 -Wall nonheap.c nonheap.c: In function ‘add_string’: nonheap.c:24:19: warning: ‘reallocarray’ called on unallocated object ‘strings’ [-Wfree-nonheap-object] 24 | strings = reallocarray(strings, ++*n, sizeof(const char *)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ nonheap.c:21:44: note: declared here 21 | add_string(size_t *restrict n, const char *strings[restrict *n], | ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~ alx@debian:~/tmp$ gcc-14 -Wall nonheap.c nonheap.c: In function ‘add_string’: nonheap.c:24:19: warning: ‘reallocarray’ called on unallocated object ‘strings’ [-Wfree-nonheap-object] 24 | strings = reallocarray(strings, ++*n, sizeof(const char *)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ nonheap.c:21:44: note: declared here 21 | add_string(size_t *restrict n, const char *strings[restrict *n], | ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~ If I change the function to have the parameter be `const char **restrict strings`, the warning vanishes.
With -O3, the warning also vanishes, as the function is probably inlined, and there's no VLA parameter any more. alx@debian:~/tmp$ gcc-14 -Wall -O3 nonheap.c alx@debian:~/tmp$ gcc-13 -Wall -O3 nonheap.c alx@debian:~/tmp$
Confirmed, reduced testcase: ``` const char ** add_string(int *restrict n, const char *strings[restrict *n]) { strings = __builtin_realloc(strings, *n); if (!strings) return 0; return strings; } ``` Note if we had `int n` instead of a pointer, then there would be no warning.
Another testcase: ``` struct a { int n; }; const char ** add_string(struct a n, const char *strings[restrict n.n]) { strings = __builtin_realloc(strings, n.n); if (!strings) return 0; return strings; } ```