Skip to content

arm_linux: Add missing memory barrier to atomic_cmpxchg #1234

Open
taiki-e wants to merge 3 commits into
rust-lang:mainfrom
taiki-e:arm-linux-barrier
Open

arm_linux: Add missing memory barrier to atomic_cmpxchg #1234
taiki-e wants to merge 3 commits into
rust-lang:mainfrom
taiki-e:arm-linux-barrier

Conversation

@taiki-e

@taiki-e taiki-e commented Jul 11, 2026

Copy link
Copy Markdown
Member

This PR contains three commits. The main fix is the last one, and the first two address minor issues such as documentation that I noticed when writing the main fix. I would suggest reviewing by commit, but I can split them into separate PRs if necessary.


Currently, atomic_cmpxchg returns the value obtained from the first relaxed load as-is without calling the kuser helper when comparison fails:

let curval_aligned = unsafe { atomic_load_aligned::<T>(aligned_ptr) };
let curval = extract_aligned(curval_aligned, shift, mask);
if curval != oldval {
return curval;
}

This is equivalent to compare_exchange(SeqCst, Relaxed), but the __sync builtins are expected to have SeqCst semantics in both the success and failure paths, so this is unsound.

This PR fixes this by adding a memory barrier to failure path:

let curval_aligned = unsafe { atomic_load_aligned::<T>(aligned_ptr) };
let curval = extract_aligned(curval_aligned, shift, mask);
if curval != oldval {
// __sync builtins must have SeqCst semantics. So, failure path, which returns early
// without calling __kuser_cmpxchg, must emits a memory barrier.
__kuser_memory_barrier();
return curval;
}

Context and Disclosure: This bug had been observed for several years as a rare stress test failure in portable-atomic's CI when testing pre-v6 ARM Linux on ARM hardware (https://gist.github.com/taiki-e/31962f6efe8cc9bc06aa6869bbceb656). In my past investigations, I suspected the bug was with the algorithm used in portable-atomic, so I was unable to identify the cause, but I recently identified the cause by investigating a wider scope with the help of LLMs. (All changes in this PR were written by me.)

@tgross35 tgross35 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks reasonable to me, couple questions for my understanding:

  1. This only shows up when multiple atomics are involved, right (hence seqcst) ? I think the single-atomic pathing was fine here but can't convince myself of it.
  2. Is there a C implementation somewhere that we can reference?

Also I'm planning to add the middle bit of your PR message into the third commit's description so there's some context in the history, feel free to do this yourself if you prefer.

View changes since this review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants