External Publication
Visit Post

Include racy reads in Rust memory model with `MaybeInvalid<T>`

Rust Internals [Unofficial] May 14, 2026
Source

josh:

I'm suggesting that it is potentially useful, from a type-system perspective, to tag things for which racy reads are permitted , so that writers of such things know that what they write may be subject to racy reads.

Oh yeah, Atomic* is useful as a type. But IMO we have to have an operational semantics figured out before we can even start discussing what the most ergonomic API should look like.

josh:

Then that doesn't seem like a useful model for racy reads, unless I'm missing something here.

It is useful for SeqLock, which is stated as motivation at the top of this thread. It is also the only thing we could conceivably do for racy non-atomic reads without breaking all the optimizations so I really don't know what else you have in mind.

If you want "I definitely get the old or new value" kind of behavior (which you definitely need if the value is a pointer you are planning to load from -- right?), then there's no way around using atomics. Lucky enough we already have AtomicPtr so you can already do that. I genuinely don't know which gap in Rust's concurrency support you are seeing here. (There is a gap around SeqLocks, but as you will know, there you don't "either old or new value". SeqLocks are entirely fine with reading arbitrary garbage when there is a race because they will verify whether there was a race before doing anything with the data.)

EDIT: Re-reading what you wrote, maybe you are talking about abstractions that could already be implemented as a library in Rust today, but that you think should be added to the standard library? If so, you have come to the wrong thread -- here we are discussing things that need extensions to the operational semantics of Rust, things that cannot already be implemented as a library. Maybe that is the source of our misunderstanding.

josh:

People do implement seqlocks in C

I was assuming that we are talking about UB-free Standard C. People of course write C code that typically generates the correct assembly, but I wouldn't say this is "supported in C" if you have to write code with UB to achieve that. And conversely, if you are okay with writing code with UB, you can do that in Rust as well and you will probably get the right assembly most of the time if you are careful enough. But in neither case does the compiler actually guarantee that this will keep working.

The Linux kernel is its own special beast, it uses volatile accesses instead of atomics and then relies on being "too big to fail" to get compilers to generate the desired code despite the UB. But note that no actual semantics exist for "Kernel C" so it's not even clear what "correct compilation" means beyond "looking at some examples and manually checking if the assembly does the right thing". We typically use an operational semantics so that we can argue about correctness one optimization at a time (also see the warm-up part of this blog post); for "Kernel C", this is not possible, so all we can do is test and hope. I don't deny that this works in practice, but in Rust we typically don't accept that kind of reasoning.

Discussion in the ATmosphere

Loading comments...