Skip to content

Static promotion allows sharing non-Sync values across threads (maybe unsound?) #142233

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
theemathas opened this issue Jun 9, 2025 · 4 comments
Labels
C-bug Category: This is a bug. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@theemathas
Copy link
Contributor

use std::marker::PhantomData;

// Doesn't implement Sync or Send
#[allow(dead_code)] 
struct Foo(i32, PhantomData<*mut ()>);

const X: &Foo = &Foo(123, PhantomData);

fn main() {
    let thread = std::thread::spawn(|| {
        println!("{:p}", X);
    });
    println!("{:p}", X);
    thread.join().unwrap();
}

Since Foo does not implement Sync, Rust is supposed to prevent me from getting a &Foo that points to the same place, and access it from two different threads at the same time.

However, the above code manages to obtain a &Foo in two different threads simultaneously. The code then prints the addresses of the two references. This code somehow compiles, and it prints the same address twice, demonstrating that the two references indeed point to the same address.

I suspect that this is probably unsound, because this may break invariants that external libraries rely on. (For example, a library might define a non-Sync type, and assume that if two references to this type have the same address, then they are from the same thread.) Although, I am unable to find a way to cause undefined behavior using just std, since trying to put interior mutability inside Foo causes the code to stop compiling.

@rustbot labels +I-unsound

Meta

Reproducible on the playground with 1.89.0-nightly (2025-06-08 6ccd4476036edfce364e)

@theemathas theemathas added the C-bug Category: This is a bug. label Jun 9, 2025
@rustbot rustbot added needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Jun 9, 2025
@theemathas
Copy link
Contributor Author

Another variant (doesn't rely on consts or llvm deduplication):

use std::marker::PhantomData;

// Doesn't implement Sync or Send
#[allow(dead_code)]
struct Foo(i32, PhantomData<*mut ()>);

fn get_foo() -> &'static Foo {
    &Foo(123, PhantomData)
}

fn main() {
    let mut threads = vec![];
    for _ in 0..5 {
        threads.push(std::thread::spawn(|| {
            println!("{:p}", get_foo());
        }));
    }
    for thread in threads {
        thread.join().unwrap();
    }
}

@Noratrieb
Copy link
Member

Noratrieb commented Jun 9, 2025

@oli-obk @RalfJung friends of promotion

@Noratrieb Noratrieb added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Jun 9, 2025
@bjorn3
Copy link
Member

bjorn3 commented Jun 9, 2025

Seems related to #49206.

@RalfJung
Copy link
Member

RalfJung commented Jun 9, 2025

Yeah I think this is a duplicate of #49206. So far I have no idea how to fix that one... we can't just forbid constant of !Sync type since raw pointers are !Sync so that would forbid way too much (also see #54424).

@RalfJung RalfJung closed this as completed Jun 9, 2025
@apiraino apiraino removed the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Jun 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants