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>

Reply via email to