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?

Reply via email to