https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128131

            Bug ID: 128131
           Summary: __builtin_object_size of strndup result is too small,
                    valid code aborts with _FORTIFY_SOURCE
           Product: gcc
           Version: 13.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: lzy20000419 at outlook dot com
  Target Milestone: ---

```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char b[4] = "abcd";          /* no terminating NUL */
int main (void)
{
  char *p = strndup (b, 4);  /* allocates 5 bytes: "abcd\0" */
  if (!p) return 2;
  printf ("bos0=%zu bdos0=%zu\n", __builtin_object_size (p, 0),
__builtin_dynamic_object_size (p, 0));
  strcpy (p, "abcd");        /* 5 bytes into a 5-byte block */
  puts (p);
  free (p);
  return 0;
}
```

$ gcc -O2 -D_FORTIFY_SOURCE=2 t.c && ./a.out
*** buffer overflow detected ***: terminated
Aborted

There is also a -Wstringop-overflow warning, "writing 5 bytes into a region of
size 4". Expected: prints abcd. strndup does not need a NUL within the first n
bytes of s, so the result here is 5 bytes, but __builtin_object_size (p, 0) is
4.

A second case: with a run-time bound of SIZE_MAX, n + 1 wraps to 0, so

```c
__attribute__((noipa)) char *dup_limited (const char *s, size_t limit)
{ char *p = strndup (s, limit); if (p) strcpy (p, s); return p; }
... dup_limited ("hello", SIZE_MAX);
```

aborts with -O2 -D_FORTIFY_SOURCE=3, and there is no warning.

It fails with 13.1 through 16.2 and trunk. 12.2 returns -1 (no strndup
support), so it doesn't abort there.

https://godbolt.org/z/o6sjfaenh (left gcc 12.2, right trunk)

Disclaimer: This test case was generated by a fuzzer, and the report was
written with LLM assistance.

Reply via email to