1

The following excerpt is taken from the website https://lwn.net/Articles/262464/ and it is dealing with read-inconsistencies of shared data structures (for which there was the RCU created):

p = gp;
if (p != NULL) {
  do_something_with(p->a, p->b, p->c);
}

Although this code fragment might well seem immune to misordering, unfortunately, the DEC Alpha CPU [PDF] and value-speculation compiler optimizations can, believe it or not, cause the values of p->a, p->b, and p->c to be fetched before the value of p! This is perhaps easiest to see in the case of value-speculation compiler optimizations, where the compiler guesses the value of p, fetches p->a, p->b, and p->c, then fetches the actual value of p in order to check whether its guess was correct. This sort of optimization is quite aggressive, perhaps insanely so, but does actually occur in the context of profile-driven optimization.

It is unclear to me whether the above code is meant to produce erroneous (*) values in the access to p->a etc. which scares the sh.t out of me, or if it is meant as "other CPUs can observe the fetches in another than the written (in source) order" which would be totally,unsurprisingly ok to me.

If the first interpretation is correct I consider systems (compilers) which allow this kind of behaviour broken. My question is if this thing still exists, even when the prevalent architecture (Alpha) already may have vanished.

(*) Erroneous values in the sense of p->a being from one record and p->b from another or something worse

PS: I didn't check but I assume the gp variable to be correctly decorated with atomic or the like.

Vroomfondel
  • 2,704
  • 1
  • 15
  • 29
  • *Erroneous values in the sense of `p->a` being from one record and `p->b` from another or something worse* If `p` is changing between any of the evaluations of `p` in your posted code, that's a race condition no matter what and likely UB to boot. – Andrew Henle Feb 12 '21 at 18:27
  • @AndrewHenle The RCU discussion more or less insinuates non-changing data under the pointers. Updates, as far as I understand are non-destructive to data already residing in an RCU controlled data structure - thats the whole point of RCU it seems – Vroomfondel Feb 12 '21 at 19:34

1 Answers1

1

C++

That article was written in 2007, so it predates C++11.

C++11 was the first to define anything about threads in the standard, and with it defines1 what does or doesn't constitute a data race.

Under the current rules, I believe your conclusion is basically correct--with the quoted code, evaluating p->a, p->b and/or p->c when p==NULL would violate the requirements of the standard, except under the as-if rule (i.e., if the system could assure that evaluating them had no visible effects, even if p was a null pointer).

C

The story here is pretty much the same--the C11 standard was the first to define threading and how sequencing works when you use them. So, when the article was written, the standard didn't have any rules about it. Although they don't use the same terminology, the C and C++ committees have coordinated on this, so I believe they at least intend for the rules in the two languages to be the same in this regard.


1. Well, it tries to, anyway--if memory serves, a few holes have been found in how things were defined in the 2011 standard, so there have been updates in the newer standards. But the main point is that before the 2011 standard, it didn't even try.
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • So the conclusion is that pre-11 language definition plus nasty CPU architectures produced a combination which is effectively _wrong_ under an ostensible understanding of how C code should work? – Vroomfondel Feb 12 '21 at 19:43
  • 1
    @Vroomfondel: I'd probably phrase it a bit differently, but yeah. – Jerry Coffin Feb 12 '21 at 20:32