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.