Re: [PATCH 1/2] compiler.h: Introduce ptr_eq() to preserve address dependency

Alan Stern
2024-09-28T21:15:35Z

On Sat, Sep 28, 2024 at 11:55:22AM -0400, Mathieu Desnoyers wrote:
> On 2024-09-28 17:49, Alan Stern wrote:
> > On Sat, Sep 28, 2024 at 11:32:18AM -0400, Mathieu Desnoyers wrote:
> > > On 2024-09-28 16:49, Alan Stern wrote:
> > > > On Sat, Sep 28, 2024 at 09:51:27AM -0400, Mathieu Desnoyers wrote:
> > > > > equality, which does not preserve address dependencies and allows the
> > > > > following misordering speculations:
> > > > >
> > > > > - If @b is a constant, the compiler can issue the loads which depend
> > > > > on @a before loading @a.
> > > > > - If @b is a register populated by a prior load, weakly-ordered
> > > > > CPUs can speculate loads which depend on @a before loading @a.
> > > >
> > > > It shouldn't matter whether @a and @b are constants, registers, or
> > > > anything else. All that matters is that the compiler uses the wrong
> > > > one, which allows weakly ordered CPUs to speculate loads you wouldn't
> > > > expect it to, based on the source code alone.
> > >
> > > I only partially agree here.
> > >
> > > On weakly-ordered architectures, indeed we don't care whether the
> > > issue is caused by the compiler reordering the code (constant)
> > > or the CPU speculating the load (registers).
> > >
> > > However, on strongly-ordered architectures, AFAIU, only the constant
> > > case is problematic (compiler reordering the dependent load), because
> >
> > I thought you were trying to prevent the compiler from using one pointer
> > instead of the other, not trying to prevent it from reordering anything.
> > Isn't this the point the documentation wants to get across when it says
> > that comparing pointers can be dangerous?
>
> The motivation for introducing ptr_eq() is indeed because the
> compiler barrier is not sufficient to prevent the compiler from
> using one pointer instead of the other.
>
> But it turns out that ptr_eq() is also a good tool to prevent the
> compiler from reordering loads in case where the comparison is
> done against a constant.

Isn't that the same thing? A constant pointer like &x is still a
pointer. What you want to do is compare p with &x without allowing the
compiler to then replace *p with *&x (or just x).

> > Isn't it true that on strongly ordered CPUs, a compiler barrier is
> > sufficient to prevent the rcu_dereference() problem? So the whole idea
> > behind ptr_eq() is that it prevents the problem on all CPUs.
>
> Correct. But given that we have ptr_eq(), it's good to show how it
> equally prevents the compiler from reordering address-dependent loads
> (comparison with constant) *and* prevents the compiler from using
> one pointer rather than the other (comparison between two non-constant
> pointers) which affects speculation on weakly-ordered CPUs.

I don't see how these two things differ from each other. In the
comparison-with-a-constant case, how is the compiler reordering
anything? Isn't it just using the constant address rather than the
loaded pointer and thereby breaking the address dependency?

Alan stern