Re: [patch V2 1/8] signal: Prevent exec() race

From: Peter Zijlstra

Date: Fri Sep 11 2026 - 06:28:39 EST


On Fri, Sep 11, 2026 at 11:58:04AM +0200, Frederic Weisbecker wrote:
> Le Thu, Sep 10, 2026 at 03:28:43PM +0200, Peter Zijlstra a écrit :

> > The way data dependencies work in this case is a LOAD->LOAD ordering.
> > The LOAD-ACQUIRE that is part of LOCK must happen after the initial
> > load. And then the later load is constrained by the ACQUIRE.
> >
> > So LOAD(B) must resolve in order to do LOAD_ACQUIRE(B->lock.value).
>
> Ok I must confess that's not a pattern I'm used to and therefore it's
> still a bit counter-intuitive to me. I hope we can document that somehow
> somewhere.

One way of looking at it is the computation for the address of
&B->lock.value.

A void *r = LOAD(B); // B
B r += offsetof(typeof(*B), lock); // &B->lock
spin_lock(r)
C r += offsetof(typeof(B->lock), value); // &B->lock.value
for (;;)
D v = LOAD_ACQUIRE(r);
if (!v && !cmpxchg_relaxed(r, 0, 1))
break;
cpu_relax();

Note how the LOAD_ACQUIRE() at D depends on the computation of C, and B,
which in turn depend on the load of A.

If A does not complete, B,C cannot compute the address for the load of
D. Therefore A must come before D.