Skip to content

Commit

Permalink
treat addr_of!(STATIC_MUT) implied deref as safe
Browse files Browse the repository at this point in the history
The implied deref introduced during HIR->THIR lowering is only
used to create place expressions, it lacks unsafe semantics.
  • Loading branch information
workingjubilee committed Jun 1, 2024
1 parent ada5e2c commit b34ded0
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 9 deletions.
18 changes: 16 additions & 2 deletions compiler/rustc_mir_build/src/check_unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct UnsafetyVisitor<'a, 'tcx> {
/// When inside the LHS of an assignment to a field, this is the type
/// of the LHS and the span of the assignment expression.
assignment_info: Option<Ty<'tcx>>,
in_addr_of: bool,
in_union_destructure: bool,
param_env: ParamEnv<'tcx>,
inside_adt: bool,
Expand Down Expand Up @@ -170,6 +171,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
safety_context,
body_target_features: self.body_target_features,
assignment_info: self.assignment_info,
in_addr_of: false,
in_union_destructure: false,
param_env: self.param_env,
inside_adt: false,
Expand Down Expand Up @@ -449,11 +451,22 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
}
}
}
ExprKind::AddressOf { .. } => {
// we want to forgive one deref, so addr_of!(STATIC_MUT) works
self.in_addr_of = true;
}
ExprKind::Deref { arg } => {
// during HIR -> THIR, we synthesize a pointer to the static and then deref it
let allow_implicit_static_deref = self.in_addr_of;
// we don't want to accidentally allow addr_of!(*STATIC_MUT)
self.in_addr_of = false;

if let ExprKind::StaticRef { def_id, .. } | ExprKind::ThreadLocalRef(def_id) =
self.thir[arg].kind
{
if self.tcx.is_mutable_static(def_id) {
if self.tcx.is_mutable_static(def_id) && allow_implicit_static_deref {
// we're only taking the address of the implicit place expr, it's fine
} else 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);
Expand Down Expand Up @@ -956,8 +969,9 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
hir_context: hir_id,
body_target_features,
assignment_info: None,
in_union_destructure: false,
param_env: tcx.param_env(def),
in_addr_of: false,
in_union_destructure: false,
inside_adt: false,
warnings: &mut warnings,
suggest_unsafe_block: true,
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/consts/const_refs_to_static.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const C1: &i32 = &S;
const C1_READ: () = {
assert!(*C1 == 0);
};
const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) };
const C2: *const i32 = std::ptr::addr_of!(S_MUT);

fn main() {
assert_eq!(*C1, 0);
Expand Down
9 changes: 3 additions & 6 deletions tests/ui/consts/mut-ptr-to-static.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,9 @@ static mut STATIC: u32 = 42;
static INTERIOR_MUTABLE_STATIC: SyncUnsafeCell<u32> = SyncUnsafeCell::new(42);

// A static that mutably points to STATIC.
static PTR: SyncPtr = SyncPtr {
foo: unsafe { ptr::addr_of_mut!(STATIC) },
};
static INTERIOR_MUTABLE_PTR: SyncPtr = SyncPtr {
foo: ptr::addr_of!(INTERIOR_MUTABLE_STATIC) as *mut u32,
};
static PTR: SyncPtr = SyncPtr { foo: ptr::addr_of_mut!(STATIC) };
static INTERIOR_MUTABLE_PTR: SyncPtr =
SyncPtr { foo: ptr::addr_of!(INTERIOR_MUTABLE_STATIC) as *mut u32 };

fn main() {
let ptr = PTR.foo;
Expand Down
10 changes: 10 additions & 0 deletions tests/ui/static/addr-of-static-mut.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//@ check-pass

// see https://github.com/rust-lang/rust/issues/125833
// notionally, taking the address of a static mut is a safe operation,
// as we only point at it instead of generating a true reference to it
static mut FLAG: bool = false;
fn main() {
let p = std::ptr::addr_of!(FLAG);
println!("{p:p}")
}

0 comments on commit b34ded0

Please sign in to comment.