https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88973
Martin Sebor <msebor at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |RESOLVED Resolution|--- |INVALID --- Comment #4 from Martin Sebor <msebor at gcc dot gnu.org> --- I've created a test case using the canonicalize_pathname function showing that it does, in fact, cause an overlap to take place. The following line in the output of the test case strcpy (0x217f265 = "//bar", 0x217f267 = "bar"): 3 shows that strcpy is being called to copy the 4 bytes "bar\0" from 0x217f267 to 0x217f265, with the last two bytes of the copy overlapping its first two bytes. $ cat canonicalize_pathname.c && gcc -DPATHNAME='"/foo///bar"' -O2 -Wall canonicalize_pathname.c && ./a.out char* strcpy (char *d, const char *s) { unsigned n = __builtin_strlen (s); __builtin_printf ("%s (%p = \"%s\", %p = \"%s\"): %u\n", __func__, d, d, s, s, n); __builtin_memcpy (d, s, n + 1); return d; } char * canonicalize_pathname (char *path) { int i, start; char stub_char, *result; result = __builtin_strdup( path ); stub_char = (*path == '/') ? '/' : '.'; i = 0; while (result[i]) { while (result[i] != '\0' && result[i] != '/') i++; start = i++; if (!result[start]) break; while (result[i] == '/') i++; if ((start + 1) != i) { strcpy( result + start + 1, result + i ); i = start + 1; } if (start > 0 && result[start - 1] == '\\') continue; if ((start && !result[i]) || (result[i] == '.' && !result[i+1])) { result[--i] = '\0'; break; } if (result[i] == '.') { if (result[i + 1] == '/') { strcpy( result + i, result + i + 1 ); i = (start < 0) ? 0 : start; continue; } if (result[i + 1] == '.' && (result[i + 2] == '/' || !result[i + 2])) { while (--start > -1 && result[start] != '/') ; strcpy( result + start + 1, result + i + 2 ); i = (start < 0) ? 0 : start; continue; } } } if (!*result) { *result = stub_char; result[1] = '\0'; } return result; } int main (void) { char *p = canonicalize_pathname (PATHNAME); __builtin_printf ("%s\n", p); } canonicalize_pathname.c: In function ‘canonicalize_pathname’: canonicalize_pathname.c:61:2: warning: ‘strcpy’ accessing 1 byte at offsets [0, 9223372036854775807] and [0, 9223372036854775807] may overlap 1 byte at offset 0 [-Wrestrict] 61 | strcpy( result + start + 1, result + i + 2 ); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ strcpy (0x217f265 = "//bar", 0x217f267 = "bar"): 3 /foo/bar