id: safety-08 original_id: P.UNS.SAS.08 level: P impact: CRITICAL clippy: mut_from_ref
Mutable Return from Immutable Parameter is Wrong
Summary
A function taking &self or &T must not return &mut T to the same data without interior mutability.
Rationale
Returning &mut from & violates Rust's aliasing rules. The caller has an immutable borrow, so they can create additional & references. Returning &mut creates mutable aliasing, which is undefined behavior.
Bad Example
// DON'T: Return &mut from &self
struct Container {
data: i32,
}
impl Container {
// WRONG: This is undefined behavior!
pub fn get_mut(&self) -> &mut i32 {
unsafe {
// Creating &mut from & is ALWAYS wrong
&mut *(&self.data as *const i32 as *mut i32)
}
}
}
// DON'T: Transmute & to &mut
fn bad_transmute<T>(reference: &T) -> &mut T {
unsafe { std::mem::transmute(reference) } // UB!
}
Good Example
use std::cell::{Cell, RefCell, UnsafeCell};
// DO: Use interior mutability types
struct Container {
data: Cell<i32>, // For Copy types
complex: RefCell<String>, // For non-Copy with runtime checks
}
impl Container {
pub fn get(&self) -> i32 {
self.data.get()
}
pub fn set(&self, value: i32) {
self.data.set(value);
}
pub fn modify_complex(&self, f: impl FnOnce(&mut String)) {
f(&mut self.complex.borrow_mut());
}
}
// DO: Use UnsafeCell for custom interior mutability
struct MyMutex<T> {
locked: std::sync::atomic::AtomicBool,
data: UnsafeCell<T>,
}
impl<T> MyMutex<T> {
pub fn lock(&self) -> MutexGuard<'_, T> {
// Acquire lock...
MutexGuard { mutex: self }
}
}
struct MutexGuard<'a, T> {
mutex: &'a MyMutex<T>,
}
impl<T> std::ops::DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
// SAFETY: We hold the lock, so exclusive access is guaranteed
unsafe { &mut *self.mutex.data.get() }
}
}
The Only Valid Pattern
The ONLY way to get &mut from & is through UnsafeCell:
use std::cell::UnsafeCell;
struct ValidInteriorMut {
data: UnsafeCell<i32>,
}
impl ValidInteriorMut {
// This is sound ONLY because UnsafeCell opts out of aliasing rules
// AND we guarantee exclusive access (e.g., through a lock)
pub fn get_mut(&self) -> &mut i32 {
// Must ensure no other references exist!
unsafe { &mut *self.data.get() }
}
}
Checklist
- Am I trying to return &mut from a & method?
- If yes, am I using UnsafeCell or a type built on it?
- Am I guaranteeing exclusive access before creating &mut?
- Would Cell, RefCell, or Mutex solve my problem safely?
Related Rules
ptr-05: Don't manually convert *const to *mutsafety-02: Verify safety invariants
你可能感兴趣的文章
Do Not Expose Raw Pointers in Public APIs
Unsafe Code Authors Must Verify Safety Invariants
Ensure Consistent Data Layout for Custom Types
Add Safety Section in Docs for Public Unsafe Functions
Do Not Use Union Variants Across Different Lifetimes
Use MaybeUninit
Ensure C-ABI Compatibility for Strings Between Rust and C
Do Not Dereference Pointers Cast to Misaligned Types
Use Dedicated Opaque Type Pointers Instead of c_void for C Opaque Types