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

From: Frederic Weisbecker

Date: Fri Sep 11 2026 - 08:43:40 EST


Le Fri, Sep 11, 2026 at 12:22:03PM +0200, Peter Zijlstra a écrit :
> 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.

Right, it's just that acquire is often described as ordering access after
a single memory target (matching release before that same single memory target).
But I'm discovering that this property also applies to a memory target that
depends on an actual target, so to speak :o)

Anyway yes, I get the idea now, thanks for the patient explanations!