Rollup merge of #125834 - workingjubilee:weaken-thir-unsafeck-for-addr-of-static-mut, r=compiler-errors
treat `&raw (const|mut) UNSAFE_STATIC` implied deref as safe Fixes rust-lang/rust#125833 As reported in that and related issues, `static mut STATIC_MUT: T` is very often used in embedded code, and is in many ways equivalent to `static STATIC_CELL: SyncUnsafeCell<T>`. The Rust expression of `&raw mut STATIC_MUT` and `SyncUnsafeCell::get(&STATIC_CELL)` are approximately equal, and both evaluate to `*mut T`. The library function is safe because it has *declared itself* to be safe. However, the raw ref operator is unsafe because all uses of `static mut` are considered unsafe, even though the static's value is not used by this expression (unlike, for example, `&STATIC_MUT`). We can fix this unnatural difference by simply adding the proper exclusion for the safety check inside the THIR unsafeck, so that we do not declare it unsafe if it is not. While the primary concern here is `static mut`, this change is made for all instances of an "unsafe static", which includes a static declared inside `extern "abi" {}`. Hypothetically, we could go as far as generalizing this to all instances of `&raw (const|mut) *ptr`, but today we do not, as we have not actually considered the range of possible expressions that use a similar encoding. We do not even extend this to thread-local equivalents, because they have less clear semantics.
This commit is contained in:
commit
1b4b0e9a4d
13 changed files with 133 additions and 13 deletions
|
@ -466,6 +466,24 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
ExprKind::AddressOf { arg, .. } => {
|
||||
if let ExprKind::Scope { value: arg, .. } = self.thir[arg].kind
|
||||
// THIR desugars UNSAFE_STATIC into *UNSAFE_STATIC_REF, where
|
||||
// UNSAFE_STATIC_REF holds the addr of the UNSAFE_STATIC, so: take two steps
|
||||
&& let ExprKind::Deref { arg } = self.thir[arg].kind
|
||||
// FIXME(workingjubiee): we lack a clear reason to reject ThreadLocalRef here,
|
||||
// but we also have no conclusive reason to allow it either!
|
||||
&& let ExprKind::StaticRef { .. } = self.thir[arg].kind
|
||||
{
|
||||
// A raw ref to a place expr, even an "unsafe static", is okay!
|
||||
// We short-circuit to not recursively traverse this expression.
|
||||
return;
|
||||
// note: const_mut_refs enables this code, and it currently remains unsafe:
|
||||
// static mut BYTE: u8 = 0;
|
||||
// static mut BYTE_PTR: *mut u8 = unsafe { addr_of_mut!(BYTE) };
|
||||
// static mut DEREF_BYTE_PTR: *mut u8 = unsafe { addr_of_mut!(*BYTE_PTR) };
|
||||
}
|
||||
}
|
||||
ExprKind::Deref { arg } => {
|
||||
if let ExprKind::StaticRef { def_id, .. } | ExprKind::ThreadLocalRef(def_id) =
|
||||
self.thir[arg].kind
|
||||
|
|
|
@ -939,9 +939,11 @@ impl<'tcx> Cx<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// We encode uses of statics as a `*&STATIC` where the `&STATIC` part is
|
||||
// a constant reference (or constant raw pointer for `static mut`) in MIR
|
||||
// A source Rust `path::to::STATIC` is a place expr like *&ident is.
|
||||
// In THIR, we make them exactly equivalent by inserting the implied *& or *&raw,
|
||||
// but distinguish between &STATIC and &THREAD_LOCAL as they have different semantics
|
||||
Res::Def(DefKind::Static { .. }, id) => {
|
||||
// this is &raw for extern static or static mut, and & for other statics
|
||||
let ty = self.tcx.static_ptr_ty(id);
|
||||
let temp_lifetime = self
|
||||
.rvalue_scopes
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue