Skip to content

AtomStoreCell can create aliasing mutable references #8362

Closed
@LegionMammal978

Description

@LegionMammal978

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)

https://play.swc.rs/?version=1.3.100&code=H4sIAAAAAAAAA12Pz26DMAyH73kKj0ObVP2zc9ohtWh9AR5gysCRkAKZjCmHinefQ5nUzpco9pd8Px82augReq6t%2FY5EcbS2iOPx0R2rL8ex7a09y1FyJCwwhKNSPdNQMXzemlAyndYu16u1gxfMCNe0PyFN4UqxPT3hOfhIICq5bMVPOdwVSPkOvLD65sKA9tlgYJdDicEvZKqZ2r%2FvU0xdpPSXeQusdUaIHSNh%2FZYZyfL35B%2BFIsjMPJ3UpJT4W9d02iyWgAyVbAMfr9tZW6N3Q2C9%2FJ2gR44ls16lVlJPanP4BaeOXFBqAQAA&config=H4sIAAAAAAAAA1WPSw7DIAwF9zkF8rrbdtE79BAWdSIifrKJVBTl7iUE0maH3xsz8jooBbNoeKq1PMsQkYX4nEsi2Sf8lARIOxTNJia49XaWvRrRCtVoOxpIyBOluiX3hoMNQajjLXPGmzH%2FC3VwkUnkCu4o%2BsnSVTc0JbjwXmrZDkk50qF%2FwA%2FqsvNjMPLqm4kXGrYvhlQioBQBAAA%3D

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions