https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128094
Jakub Jelinek <jakub at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |jakub at gcc dot gnu.org
--- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
This is just a bogus container_of macro.
C says here:
"For the purposes of these operators, a pointer to an object that is not an
element of an array behaves the same as a pointer to the first element of an
array of length one with the type of the object as its element type.
When an expression that has integer type is added to or subtracted from a
pointer, the result has the type of the pointer operand. If the pointer operand
points to an element of an array object, and the array is large enough, the
result points to an element offset from the original element such that the
difference of the subscripts of the resulting and original array elements
equals the integer expression.
In other words, if the expression P points to the i-th element of an array
object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the
value n) point to, respectively, the i + n-th and i − n-th elements of the
array object, provided they exist. Moreover, if the expression P points to the
last element of an array object, the expression (P)+1 points one past the last
element of the array object, and if the expression Q points one past the last
element of an array object, the expression
(Q)-1 points to the last element of the array object. If the pointer operand
and the result do not point to elements of the same array object or one past
the last element of the array object, the behavior is undefined. If the
addition or subtraction produces an overflow, the behavior is undefined. If the
result points one past the last element of the array object, it shall not be
used as the operand of a unary * operator that is evaluated."
In your testcase, &a[argc].x points to the a[argc].x object (subobject of the
complete object a). It is treated as if it is an array of a single element,
and then you try to subtract 8 from that, but that is out of bounds of the
a[argc].x object, so undefined behavior. And __builtin_dynamic_object_size
reflects that UB in its return value by returning 0.
If you instead use char *x = (char *)&a[argc] + offsetof (struct s, x); then
the pointer points to within the a[argc] object and so __bdos will return 8.
If the container_of macro performs the subtraction in uintptr_t type instead of
pointer arithmetics, it doesn't invoke UB, just implementation defined behavior
and __bdos will also return 8.