https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86259
--- Comment #25 from rguenther at suse dot de <rguenther at suse dot de> --- On July 14, 2018 2:26:06 AM GMT+02:00, "msebor at gcc dot gnu.org" <gcc-bugzi...@gcc.gnu.org> wrote: >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. Istr the proposal suggests a -fno-provenance option. How would we handle these cases with that?