https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86259
--- Comment #24 from Martin Sebor <msebor at gcc dot gnu.org> --- The code in example #21 has the same bug: union U u; u.s = (struct S){0, 0, 0}; char *bp = u.s.b; // <<< bp points to u.s.b uintptr_t sp_ip = (uintptr_t)bp - offsetof(struct S,b); // sp_ip has u.s.b's provenance strcpy(u.xx, "abcdefghijk"); size_t len = strlen((char *)(union U *)sp_ip + 4); // still the same provenance puts(len == 7 ? "YES" : "NO"); The strlen call is undefined because (char*)sp_ip is known to point just past the last element of u.s.b. It wouldn't matter if there happened to be a valid string at that address -- there isn't in this case because what's there is a char[4] with no terminating NUL. The pointer wasn't derived from that address. The pointer was derived from u.s.b and points to u.s.b + sizeof u.s.b, and there can never be anything valid beyond the end of an object. Compile the test case with -fdump-tree-fre1=/dev/stdout to see what GCC sees: bp.0_1 = (long unsigned int) &u.s.b; sp_ip_9 = bp.0_1 + 18446744073709551612; MEM[(char * {ref-all})&u] = MEM[(char * {ref-all})"abcdefghijk"]; _4 = __builtin_strlen (&u.s.b); The rule to keep in mind is that pointer arithmetic is only valid within the boundaries of the smallest subobject it points to. This applies to structs as much as arrays. Just like it's not valid to increment a pointer from a[0][1] to a[1][0] and dereference the latter in 'char a[2][2]; it's not valid to increment a pointer to one struct member to point to another and dereference it.