AtomStoreCell can create aliasing mutable references · Issue #8362 · swc-project/swc (original) (raw)
Describe the bug
The swc_atoms::AtomStoreCell::atom()
function creates a &mut
reference from *self.0.get()
. The safety comment notes that "We can skip the borrow check of RefCell
because this API enforces a safe contract." However, this is incorrect, since the function reenters user code to call .into()
, and reenters it more times to allocate memory, and these can potentially call back into .atom()
, creating a second &mut
reference.
Input code
use std::borrow::Cow; use swc_atoms::AtomStoreCell;
struct EvilStr<'a>(&'a AtomStoreCell);
impl<'a> From<EvilStr<'a>> for Cow<'a, str> { fn from(value: EvilStr<'a>) -> Self { value.0.atom(Cow::Borrowed("reentered!")); Cow::Borrowed("evil") } }
fn main() { let cell = AtomStoreCell::default(); cell.atom(EvilStr(&cell)); }
Config
No response
Playground link (or link to the minimal reproduction)
SWC Info output
No response
Expected behavior
The function should detect that it has been reentered and panic.
Actual behavior
The function creates aliasing &mut
references when reentered. Miri reports the following error:
error: Undefined Behavior: not granting access to tag <1849> because that would remove [Unique for <1822>] which is strongly protected because it is an argument of call 791
--> /home/lm978/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_atoms-0.6.4/src/lib.rs:229:21
|
229 | pub fn atom<'a>(&mut self, s: impl Into<Cow<'a, str>>) -> Atom {
| ^^^^^^^^^ not granting access to tag <1849> because that would remove [Unique for <1822>] which is strongly protected because it is an argument of call 791
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <1849> was created by a SharedReadWrite retag at offsets [0x0..0x28]
--> src/main.rs:8:9
|
8 | value.0.atom(Cow::Borrowed("reentered!"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: <1822> is this argument
--> src/main.rs:15:5
|
15 | cell.atom(EvilStr(&cell));
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: BACKTRACE (of the first span):
= note: inside swc_atoms::AtomStore::atom::<'_, std::borrow::Cow<'_, str>>
at /home/lm978/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_atoms-0.6.4/src/lib.rs:229:21: 229:30
= note: inside swc_atoms::AtomStoreCell::atom::<'_, std::borrow::Cow<'_, str>>
at /home/lm978/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_atoms-0.6.4/src/lib.rs:245:18: 245:41
note: inside <impl std::convert::From<EvilStr<'_>> for std::borrow::Cow<'_, str>>::from
--> src/main.rs:8:9
|
8 | value.0.atom(Cow::Borrowed("reentered!"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: inside <EvilStr<'_> as std::convert::Into<std::borrow::Cow<'_, str>>>::into
at /home/lm978/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/convert/mod.rs:757:9: 757:22
= note: inside swc_atoms::hstr::AtomStore::atom::<'_, EvilStr<'_>>
at /home/lm978/.cargo/registry/src/index.crates.io-6f17d22bba15001f/hstr-0.2.6/src/dynamic.rs:82:24: 82:35
= note: inside swc_atoms::AtomStore::atom::<'_, EvilStr<'_>>
at /home/lm978/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_atoms-0.6.4/src/lib.rs:230:14: 230:28
= note: inside swc_atoms::AtomStoreCell::atom::<'_, EvilStr<'_>>
at /home/lm978/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_atoms-0.6.4/src/lib.rs:245:18: 245:41
note: inside main
--> src/main.rs:15:5
|
15 | cell.atom(EvilStr(&cell));
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: some details are omitted, run with MIRIFLAGS=-Zmiri-backtrace=full
for a verbose backtrace
Version
swc_atoms 0.6.4
Additional context
My last issue, #8361, was automatically rejected for linking to the Rust Playground instead of the SWC Playground; it would be helpful if there were some upfront indication about the requirements for the provided link.