Skip to content

addr_of! a static mut should not require unsafe #125833

Closed
@gfaster

Description

@gfaster

I tried this code (playground):

static mut FLAG: bool = false;
fn main() {
    let p = std::ptr::addr_of!(FLAG);
    println!("{p:p}")
}

I expected this to compile without adding an unsafe block, since the act of getting the address of the static on its own cannot(?) cause Undefined Behavior. Making addr_of! and addr_of_mut! safe when used on a static mut would make the behavior consistent with UnsafeCell::get, which has identical safety concerns in a multithreaded environment.

Meta

Exists on stable and the nightly version used by playground (2024-05-30).

Activity

added
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on May 31, 2024
workingjubilee

workingjubilee commented on May 31, 2024

@workingjubilee
Member

Making addr_of! and addr_of_mut! safe when used on a static mut would make the behavior consistent with UnsafeCell::get, which has identical safety concerns in a multithreaded environment.

It has been in general our expressed preference over time that you use static FLAG: UnsafeCell<bool> = false; (or perhaps static FLAG: AtomicBool = AtomicBool::new(false);, which is also an UnsafeCell) as static mut is quite counterintuitive in many different ways.

workingjubilee

workingjubilee commented on May 31, 2024

@workingjubilee
Member
workingjubilee

workingjubilee commented on May 31, 2024

@workingjubilee
Member

Hmm, it seems we don't take into account this around here:

ExprKind::Deref { arg } => {
if let ExprKind::StaticRef { def_id, .. } | ExprKind::ThreadLocalRef(def_id) =
self.thir[arg].kind
{
if self.tcx.is_mutable_static(def_id) {
self.requires_unsafe(expr.span, UseOfMutableStatic);
} else if self.tcx.is_foreign_item(def_id) {
self.requires_unsafe(expr.span, UseOfExternStatic);
}
} else if self.thir[arg].ty.is_unsafe_ptr() {
self.requires_unsafe(expr.span, DerefOfRawPointer);
}
}

Simple fix. I think?

gfaster

gfaster commented on May 31, 2024

@gfaster
Author

see #123758

It seems like #114447 even floats this idea exactly.

It has been in general our expressed preference over time that you use static FLAG: UnsafeCell<bool> = false;

Not being able to use UnsafeCell directly in statics isn't so nice since it isn't Sync, but there's #95439 for that. That being said, maybe I ought to write a Clippy lint for some of those alternatives, particularly for flag booleans.

I should clarify that I just ran into this when writing some code for a demonstration, so direct replacements aren't exactly applicable. Regardless, I believe the inconsistency stands.

workingjubilee

workingjubilee commented on May 31, 2024

@workingjubilee
Member

Hmm, looking at things more closely, I don't see why it's a Deref. That should be an ExprKind::AddressOf...?

gfaster

gfaster commented on May 31, 2024

@gfaster
Author

#95439 (comment) claims that arithmetic on static mut is unsafe. I'm not sure why that would be - can addr_of! violate LLVM's noalias?

Maybe something like this causes problems?

workingjubilee

workingjubilee commented on May 31, 2024

@workingjubilee
Member

I think that might be just descriptive (of the problem being discussed here).

workingjubilee

workingjubilee commented on May 31, 2024

@workingjubilee
Member

well, that was an unexpected THIR desugaring.

Expr {
    ty: *const bool
    temp_lifetime: Some(Node(1))
    span: /home/jubilee/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:2203:5: 2203:22 (#4)
    kind: 
    Scope {
        region_scope: Node(3)
        lint_level: Explicit(HirId(DefId(0:4 ~ static_mut[60a8]::main).3))
        value:
            Expr {
                ty: *const bool
                temp_lifetime: Some(Node(1))
                span: /home/jubilee/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:2203:5: 2203:22 (#4)
                kind: 
                    AddressOf {
                        mutability: Not
                        arg:
                            Expr {
                                ty: bool
                                temp_lifetime: Some(Remainder { block: 68, first_statement_index: 0})
                                span: static_mut.rs:3:41: 3:45 (#0)
                                kind: 
                                    Scope {
                                        region_scope: Node(4)
                                        lint_level: Explicit(HirId(DefId(0:4 ~ static_mut[60a8]::main).4))
                                        value:
                                            Expr {
                                                ty: bool
                                                temp_lifetime: Some(Remainder { block: 68, first_statement_index: 0})
                                                span: static_mut.rs:3:41: 3:45 (#0)
                                                kind: 
                                                    Deref {
                                                        Expr {
                                                            ty: *mut bool
                                                            temp_lifetime: Some(Remainder { block: 68, first_statement_index: 0})
                                                            span: static_mut.rs:3:41: 3:45 (#0)
                                                            kind: 
                                                                StaticRef {
                                                                    def_id: DefId(0:3 ~ static_mut[60a8]::FLAG)
                                                                    ty: *mut bool
                                                                    alloc_id: alloc1
                                                                }
                                                        }
                                                    }
                                            }
                                    }
                            }
                    }
            }
        }
    }
workingjubilee

workingjubilee commented on May 31, 2024

@workingjubilee
Member

Oh! Oh, I see, the way that this is defined is that naming a static generates an *mut Static and then derefs it, creating the appropriate place expression.

added
T-langRelevant to the language team
and removed
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on Jun 1, 2024
workingjubilee

workingjubilee commented on Jun 1, 2024

@workingjubilee
Member

PR up at #125834

workingjubilee

workingjubilee commented on Jun 1, 2024

@workingjubilee
Member

I wanted to say that the compiler should fix it by choosing a different lowering for naming STATIC_MUT, but that doesn't seem like anything reasonable to implement Soon, so I implemented my original thought of complicating the unsafety check.

added a commit that references this issue on Jul 23, 2024

Rollup merge of rust-lang#125834 - workingjubilee:weaken-thir-unsafec…

36487f8
added a commit that references this issue on Jul 23, 2024

Rollup merge of rust-lang#125834 - workingjubilee:weaken-thir-unsafec…

1b4b0e9
added a commit that references this issue on Jul 23, 2024
be60c1a
added a commit that references this issue on Jul 24, 2024
ea072f1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @traviscross@gfaster@workingjubilee@rustbot

      Issue actions

        `addr_of!` a `static mut` should not require `unsafe` · Issue #125833 · rust-lang/rust