On 09/18/2017 10:07 PM, Torvald Riegel wrote:
On Mon, 2017-09-18 at 14:19 +0200, Florian Weimer wrote:
I would like to see the GCC project to document that if the address of a
member is taken, this does not constitute an access to the object as a
whole.
That is, in the following code:
#include <stdatomic.h>
struct S {
_Atomic int a;
int b;
};
int
load_a (struct S *p)
{
return atomic_load_explicit (&p->a, memory_order_relaxed);
}
int
store_b (struct S *p, int b)
{
p->b = b;
}
If one thread calls load_a and another thread calls store_b on the same
struct S *, no data race happens.
There is no data race in this example; a and b are separate objects as
far as the memory model is concerned. That's my understanding and I
believe also the understanding in the C++ committee.
I'm not sure what the C++ standard says in this matter.
C++ may indeed have addressed this and related issues (e.g., that a
memory location which is passed by reference to a function is not
actually read in the caller).
This is an extension over the C standard because of the way “->” is
defined. C requires that E1->E2 it is evaluated as (*(E1))->E2, and *E1
is defined as an access to the entire struct, so there is a data race in
load_a with the assignment in store_b.
If ISO C really says that this is potentially a data race, then that's a
bug in the standard I'd say. I see no need to have an extension for
this (module there potentially being a real bug in the standard).
GCC relies on the implicit access to the full struct object in this case:
struct T {
int a;
int b;
};
int
opt (struct T *p1, struct T *p2)
{
p1->a = 1;
p2->b = 2;
return p1->a;
}
It optimizes the load of p1->a to 1. This is not a valid transformation
if there is no access to the entire struct object because it's the only
thing in this code which asserts the dynamic type of the memory
allocation is that of T, so that the members a and b do not alias.
This is why I think this issue is difficult to fix.
Thanks,
Florian