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

--- Comment #3 from Richard Biener <rguenth at gcc dot gnu.org> ---
Yes, the oracle assumes that for MEM[(struct ovs_list *)pos_32 + 64B] pos_32
needs to still point to some valid object (even if it's not of type ovs_list)
and a pointer to 'start' cannot be constructed from this without invoking
UB (and the pointer offsetting rules are not part of TBAA).

The MEMs appear in forwprop:

   <bb 12> :
   _15 = &member_59->elem;
   _16 = &pos_32->elem;
-  _48 = _16->prev;
-  _15->prev = _48;
-  _15->next = _16;
+  _48 = MEM[(struct ovs_list *)pos_32 + 64B].prev;
+  MEM[(struct ovs_list *)member_59 + 64B].prev = _48;
+  MEM[(struct ovs_list *)member_59 + 64B].next = _16;

but there it's already pointer arithmetic.  In .original we have

    pos = 0B;, pos = (struct member *) ((long unsigned int) start.next +
18446744073709551552);;
    goto <D.3776>;
    <D.3775>:;
    if (member->order > pos->order)
      {
        goto <D.3773>;
      }
    pos = (struct member *) ((long unsigned int) pos->elem.next +
18446744073709551552);
    <D.3776>:;
    if (&pos->elem != &start) goto <D.3775>; else goto <D.3773>;
    <D.3773>:;
    ovs_list_insert (&pos->elem, &member->elem);

where I think passing &pos->elem and &member->elem to ovs_list_insert is
already wrong since 'pos' doesn't point to a valid object if the
ultimate written destination is 'start'.

Doing the 'pos' initialization with uintptr_t isn't enough - you need to
do this all the way up to the &pos->elem computation as you say:

        // TESTED: This works:
        //ovs_list_insert((void *)((uintptr_t)pos + __builtin_offsetof(struct
member,elem)), &member->elem);

so yes, it's UB.  And UB that's not sanctioned with -fno-strict-aliasing.

Reply via email to