> On Nov 2, 2023, at 9:54 AM, Richard Biener <[email protected]> wrote:
>
> On Thu, Nov 2, 2023 at 2:50 PM Qing Zhao <[email protected]> wrote:
>>
>>
>>
>>> On Nov 2, 2023, at 3:57 AM, Richard Biener <[email protected]>
>>> wrote:
>>>
>>> On Wed, Nov 1, 2023 at 3:47 PM Qing Zhao <[email protected]> wrote:
>>>>
>>>>
>>>>
>>>>> On Oct 31, 2023, at 6:14 PM, Joseph Myers <[email protected]> wrote:
>>>>>
>>>>> On Tue, 31 Oct 2023, Qing Zhao wrote:
>>>>>
>>>>>> 2.3 A new semantic requirement in the user documentation of "counted_by"
>>>>>>
>>>>>> For the following structure including a FAM with a counted_by attribute:
>>>>>>
>>>>>> struct A
>>>>>> {
>>>>>> size_t size;
>>>>>> char buf[] __attribute__((counted_by(size)));
>>>>>> };
>>>>>>
>>>>>> for any object with such type:
>>>>>>
>>>>>> struct A *obj = __builtin_malloc (sizeof(struct A) + sz * sizeof(char));
>>>>>>
>>>>>> The setting to the size field should be done before the first reference
>>>>>> to the FAM field.
>>>>>>
>>>>>> Such requirement to the user will guarantee that the first reference to
>>>>>> the FAM knows the size of the FAM.
>>>>>>
>>>>>> We need to add this additional requirement to the user document.
>>>>>
>>>>> Make sure the manual is very specific about exactly when size is
>>>>> considered to be an accurate representation of the space available for buf
>>>>> (given that, after malloc or realloc, it's going to be temporarily
>>>>> inaccurate). If the intent is that inaccurate size at such a time means
>>>>> undefined behavior, say so explicitly.
>>>>
>>>> Yes, good point. We need to define this clearly in the beginning.
>>>> We need to explicit say that
>>>>
>>>> the size of the FAM is defined by the latest “counted_by” value. And it’s
>>>> an undefined behavior when the size field is not defined when the FAM is
>>>> referenced.
>>>>
>>>> Is the above good enough?
>>>>
>>>>
>>>>>
>>>>>> 2.4 Replace FAM field accesses with the new function ACCESS_WITH_SIZE
>>>>>>
>>>>>> In C FE:
>>>>>>
>>>>>> for every reference to a FAM, for example, "obj->buf" in the small
>>>>>> example,
>>>>>> check whether the corresponding FIELD_DECL has a "counted_by" attribute?
>>>>>> if YES, replace the reference to "obj->buf" with a call to
>>>>>> .ACCESS_WITH_SIZE (obj->buf, obj->size, -1);
>>>>>
>>>>> This seems plausible - but you should also consider the case of static
>>>>> initializers - remember the GNU extension for statically allocated objects
>>>>> with flexible array members (unless you're not allowing it with
>>>>> counted_by).
>>>>>
>>>>> static struct A x = { sizeof "hello", "hello" };
>>>>> static char *y = &x.buf;
>>>>>
>>>>> I'd expect that to be valid - and unless you say such a usage is invalid,
>>>>
>>>> At this moment, I think that this should be valid.
>>>>
>>>> I,e, the following:
>>>>
>>>> struct A
>>>> {
>>>> size_t size;
>>>> char buf[] __attribute__((counted_by(size)));
>>>> };
>>>>
>>>> static struct A x = {sizeof "hello", "hello”};
>>>>
>>>> Should be valid, and x.size represents the number of elements of x.buf.
>>>> Both x.size and x.buf are initialized statically.
>>>>
>>>>> you should avoid the replacement in such a static initializer context when
>>>>> the FAM reference is to an object with a constant address (if
>>>>> .ACCESS_WITH_SIZE would not act as an lvalue whose address is a constant
>>>>> expression; if it works fine as a constant-address lvalue, then the
>>>>> replacement would be OK).
>>>>
>>>> Then if such usage for the “counted_by” is valid, we need to replace the
>>>> FAM
>>>> reference by a call to .ACCESS_WITH_SIZE as well.
>>>> Otherwise the “counted_by” relationship will be lost to the Middle end.
>>>>
>>>> With the current definition of .ACCESS_WITH_SIZE
>>>>
>>>> PTR = .ACCESS_WITH_SIZE (PTR, SIZE, ACCESS_MODE)
>>>>
>>>> Isn’t the PTR (return value of the call) a LVALUE?
>>>
>>> You probably want to specify that when a pointer to the array is taken the
>>> pointer has to be to the first array element (or do we want to mangle the
>>> 'size' accordingly for the instrumentation?).
>>
>> Yes. Will add this into the user documentation.
>>
>>> You also want to specify that
>>> the 'size' associated with such pointer is assumed to be unchanging and
>>> after changing the size such pointer has to be re-obtained.
>>
>> What do you mean by “re-obtained”?
>
> do
>
> p = &container.array[0];
>
> after any adjustments to 'array' or 'len' again and base further accesses on
> the new 'p'.
Then for the following example form Kees:
struct foo *f;
char *p;
int i;
f = alloc(maximum_possible);
f->count = 0;
p = f->buf;
for (i; data_is_available() && i < maximum_possible; i++) {
f->count ++;
p[i] = next_data_item();
}
Will not work?
We have to change it as:
struct foo *f;
char *p;
int i;
f = alloc(maximum_possible);
f->count = 0;
p = f->buf;
for (i; data_is_available() && i < maximum_possible; i++) {
f->count ++;
p = f->buf; // add this?
p[i] = next_data_item();
}
Why?
>
>>> Plus that
>>> changes to the allocated object/size have to be performed through an
>>> lvalue where the containing type and thus the 'counted_by' attribute is
>>> visible.
>>
>> Through an lvalue with the containing type?
>>
>> Yes, will add this too.
>>
>>
>>> That is,
>>>
>>> size_t *s = &a.size;
>>> *s = 1;
>>>
>>> is invoking undefined behavior,
>>
>> right.
>>
>>> likewise modifying 'buf' (makes it a bit
>>> awkward since for example that wouldn't support using posix_memalign
>>> for allocation, though aligned_alloc would be fine).
>> Is there a small example for the undefined behavior for this?
>
> a.len = len;
> posix_memalign (&a.buf, 16, len);
>
> we would probably have to somehow instrument this.
For the above, the buffer and the size are still synchronized even after the
buffer is modified? Should we allow this?
Qing
>
>> Qing
>>>
>>> Richard.
>>>
>>>> Qing
>>>>>
>>>>> --
>>>>> Joseph S. Myers
>>>>> [email protected]
>>>>
>>