On 2025-07-07 03:05, Richard Biener wrote:
Since the intent of the .ACCESS_WITH_SIZE was to associate the storage
of count with c to prevent reordering, maybe the semantically correct
solution here is that when c is a pointer, the frontend emits:

    _2 = a->c;
    _3 = &a->count;
    _1 = .ACCESS_WITH_SIZE (_2, _3, 1, 0, -1, 0B);
    D.2964 = __builtin_dynamic_object_size (_, 1);

so a->c instead of &a->c.

Yes.  That's what I'd have expected happens?  I thought .ACCESS_WITH_SIZE
annotates the pointer, it doesn't perform an access itself - correct?  Where

Yes.

is .ACCESS_WITH_SIZE documented?  I can't find it documented in the
internals manual, internal-fn.def has

It's documented in tree-object-size.cc as:

/* Compute __builtin_object_size for a CALL to .ACCESS_WITH_SIZE,
   OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
   The 2nd, 3rd, and the 4th parameters of the call determine the size of
   the CALL:

   2nd argument REF_TO_SIZE: The reference to the size of the object,
3rd argument CLASS_OF_SIZE: The size referenced by the REF_TO_SIZE represents
     0: the number of bytes;
     1: the number of the elements of the object type;
4th argument TYPE_OF_SIZE: A constant 0 with its TYPE being the same as the TYPE
    of the object referenced by REF_TO_SIZE
6th argument: A constant 0 with the pointer TYPE to the original flexible
     array type or pointer field type.

The size of the element can be retrived from the TYPE of the 6th argument
   of the call, which is the pointer to the original flexible array type or
   the type of the original pointer field.  */

which doesn't document the return either. This should have more verbose documentation in the internals, including the rationale for its existence.

/* A function to associate the access size and access mode information
    with the corresponding reference to an object.  It only reads from the
    2nd argument.  */
DEF_INTERNAL_FN (ACCESS_WITH_SIZE, ECF_PURE | ECF_LEAF | ECF_NOTHROW, NULL)

that suggests .ACCESS_WITH_SIZE performs a read on the size.  It doesn't
say what the function returns at all.

In practice the function is a nop, it gets optimized away during RTL expansion. The aim is simply to pretend that the reference of the size may escape pointer to make sure that any preceding updates to size don't get reordered w.r.t. __builtin_dynamic_object_size since the latter could get expanded to that size.

The return value of .ACCESS_WITH_SIZE clobbering PTR (that subsequently gets passed to __builtin_dynamic_object_size) should be sufficient to fully prevent the reordering, it shouldn't have to clobber &PTR, I think.

Is the above only happening
when using __builtin_dynamic_object_size (_1, 1) or also when performing
an actual access like

  return a->c[i];

It is only for __builtin_dynamic_object_size, so it would also include ubsan/object-size sanitizer cases where it generates __builtin_dynamic_object_size calls.

Sid

Reply via email to