Am Montag, dem 31.07.2023 um 14:33 +0000 schrieb Michael Matz:
> Hello,
> 
> On Fri, 28 Jul 2023, Martin Uecker wrote:
> 
> > > > Sorry, somehow I must be missing something here.
> > > > 
> > > > If you add something you would create a new value and this may (in
> > > > an object) have random new padding.  But the "expected" value should
> > > > be updated by a failed atomic_compare_exchange cycle and then have
> > > > same padding as the value stored in the atomic. So the next cycle
> > > > should succeed.  The user would not change the representation of
> > > > the "expected" value but create a new value for another object
> > > > by adding something.
> > > 
> > > You're right that it would pass the expected value not something after an
> > > operation on it usually.  But still, expected type will be something like
> > > _BitInt(37) or _BitInt(195) and so neither the atomic_load nor what
> > > atomic_compare_exchange copies back on failure is guaranteed to have the
> > > padding bits preserved.
> > 
> > For atomic_load in C a value is returned. A value does not care about
> > padding and when stored into a new object can produce new and different
> > padding.  
> > 
> > But for atomic_compare_exchange the memory content is copied into 
> > an object passed by pointer, so here the C standard requires to
> > that the padding is preserved. It explicitely states that the effect
> > is like:
> > 
> > if (memcmp(object, expected, sizeof(*object)) == 0)
> >   memcpy(object, &desired, sizeof(*object));
> > else
> >   memcpy(expected, object, sizeof(*object));
> > 
> > > It is true that if it is larger than 16 bytes the libatomic 
> > > atomic_compare_exchange will memcpy the value back which copies the 
> > > padding bits, but is there a guarantee that the user code doesn't 
> > > actually copy that value further into some other variable?  
> > 
> > I do not think it would be surprising for C user when
> > the next atomic_compare_exchange fails in this case.
> 
> But that is a problem (the same one the cited C++ paper tries to resolve, 
> IIUC). 

I do not quite understand the paper. I can't see
how the example 3 in

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0528r0.html

could loop indefinitely with the memcpy / memcmp semantics,
but somehow the authors seem to claim this. 


>  Say you have a loop like so:
> 
> _Atomic T obj;
> ...
> T expected1, expected2, newval;
> newval = ...;
> expected1 = ...;
> do {
>   expected2 = expected1;
>   if (atomic_compare_exchange_weak(&obj, &expected2, newval);
>     break;
>   expected1 = expected2;
> } while (1);
> 
> As written this looks of course stupid, and you may say "don't do that", 
> but internally the copies might result from temporaries (compiler 
> generated or wrapper function arguments, or suchlike). 
>  Now, while 
> expected2 will contain the copied padding bits after the cmpxchg the 
> copies to and from expected1 will possibly destroy them.  Either way I 
> don't see why the above loop should be out-of-spec, so I can write it and 
> expect it to proceed eventually (certainly when the _strong variant is 
> used).  Any argument that would declare the above loop out-of-spec I would 
> consider a defect in the spec.

It is "out-of-spec" for C in the sense that it can not be
expected work with the semantics as specified in the C standard.

But I agree with you that it would be better if it just worked.

A compiler could, for example, always clear the padding when
initializing or storing atomic values.  It might also clear
the padding of the initial "expected", when it is
initialized or stored to.

But it should not clear / ignore the padding when copying 
to "expected" using atomic_compare_exhange or when comparing
to the memory content. See below why I think this would not
be helpful.

> 
> It's never a good idea to introduce reliance on padding bits.  Exactly 
> because you can trivially destroy them with simple value copies.
> 
> > > Anyway, for smaller or equal to 16 (or 8) bytes if 
> > > atomic_compare_exchange is emitted inline I don't see what would 
> > > preserve the bits.
> > 
> > This then seems to be incorrect for C.
> 
> Or the spec is.

In practice, what the semantics specified using memcpy/memcmp
allow one to do is to also apply atomic operations on non-atomic 
types.  This is not guaranteed to work by the C standard, but
in practice  people often have to do this.  For example, nobody
is going to copy a 256 GB numerical array with non-atomic types
into another data structure with atomic versions of the same
type just so that you can apply atomic operations on it. So
one simply does an unsafe cast and hopes the compiler does not
break this.

If the non-atomic struct now has non-zero values in the padding, 
and the compiler would clear those automatically for "expected", 
you would create the problem of an infinite loop (this time 
for real).


Martin







Reply via email to