Possible unsoundness on architectures without atomics #678
Labels
No labels
bug
duplicate
easy
enhancement
help wanted
invalid
question
rfc
structured-logging
wontfix
No milestone
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
gh-rust-lang/log#678
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
My understanding is that
logrelies on atomics to implement some of its functionality, especiallyset_logger()andset_max_level().It seems there is an internal "fake"
AtomicUsizeon platforms that do not provide atomics, with the assumption that no such architectures are multicore:github.com/rust-lang/log@5359483974/src/lib.rs (L451-L454)However this assumption does not hold on the RP2040 MCU, which features two Cortex-M0+ (ARMv6-M) cores.
I am not sure this actually currently results in unsoundness because it is not yet clear to me whether the instances of
AtomicUsizeare actually used in ways that could result in race conditions on these architectures.I suppose leveraging portable-atomic on architectures that do not provide atomics could help fix this, if this is an acceptable dependency for
log, which would only be required on such architectures.For context, we at Ariel OS are building an embedded OS which, among many other things, abstracts over
logand makes it easily usable on many processor architectures, making this easy to test.Note that
set_loggerhas thecfg(target_has_atomic = "ptr")attribute, i.e. it shouldn't be available if the atomic are not presentgithub.com/rust-lang/log@5359483974/src/lib.rs (L1402-L1405)In that case the
unsafeset_logger_racyhas to be used:github.com/rust-lang/log@5359483974/src/lib.rs (L1454-L1467)That doesn't make things any safer, but it means that
logisn't unsound.Pondering on this some more, it seems to be me that the platform being multicore or not is actually irrelevant, it just has to support multi-threading for this to be an issue.
I am aware of this function, but then the
logger()getter function actually relies on the happens-before relationship betweenLOGGERandSTATE:github.com/rust-lang/log@5359483974/src/lib.rs (L1506-L1521)However, on architectures without atomics,
STATEreally is not an atomic, and so this happens-before relationship is not guaranteed.Agreed. But then you'll most likely also not have threads. Personally I don't see how threads can do any cross-thread communication safely without atomics.
These MCUs—the RP2040 and the ESP32-C3 (RISC-V without the (A) extension) for instance—do support threading however, and we do support it in Ariel OS (even multicore).
This is done through critical sections on bare metal, which involve temporarily disabling interrupts (see the
critical-sectioncrate and the implementation in thecortex-mcrate for instance). These can be used to emulate atomics on architectures that do not support them, which is what portable-atomic does (when needed).Interesting, I didn't know about that -- I don't do a lot of embedded work myself.
Would calling
set_logger_racyin such a critical section be sufficient? (it's something to docs already call out: https://docs.rs/log/latest/log/fn.set_logger_racy.html#safety)The docs mention that:
So I think this is not exactly complete, as it would not be safe to call
logger()whileset_logger_racy()runs.Wrapping these calls in a critical section should indeed enforce that.