With a heavy heart, I’ve included a section in an RFC I submitted that asks to expand the definition of “unsafe” to allow marking code as “unsafe” to avoid backwards-compatibility hazards when safe code changes. The RFC may or may not be accepted, but either way, I think the question about whether we should be able to use “unsafe” to address this sort of concern deserves discussion?
Drawbacks
Expanding “unsafe”
Interior::from_outer_unsafe is not actually “unsafe” (in my
understanding of Rust’s current definition of unsafe), but it does
pose a backwards-compatibility issue: In current Rust, there is no way
that the destructor for a field of a container will run unless the
destructor for the container has also run, and it is possible that
there is Rust code in the wild that relies on this property being
true. from_outer_unsafe changes this: using this function, it’s
possible to cause a field’s destructors to be called without having
called the container’s destructor. Rust explicitly allows that failing
to call a destructor is “safe” behavior, so the from_outer_unsafe
behavior should be considered “safe” from a technical perspective.
But, borrowing an example from @eefriedman:
struct MaybeCrashOnDrop { c: bool }
impl Drop for MaybeCrashOnDrop {
fn drop(&mut self) {
if self.c {
unsafe { *(1 as *mut u8) = 0 }
}
}
}
pub struct InteriorUnsafe { m: MaybeCrashOnDrop }
impl InteriorUnsafe {
pub fn new() -> InteriorUnsafe {
InteriorUnsafe { m: MaybeCrashOnDrop{ c: true } }
}
}
impl Drop for InteriorUnsafe {
fn drop(&mut self) {
self.m.c = false;
}
}
The above program would not crash with safe code in current Rust,
but could be made to crash, by safe code, if Interior::from_outer
were made safe.
An alternative design is discussed below under Alternatives, but I
could not identify an alternative that did all of the following:
- Preserved the current definition of unsafe;
- Did not pose a backwards-compatibility risk;
- Integrated the implementations of
Drop and DropInterior.
As such, this proposal requires expanding the definition of "unsafe"
to also include “backwards compatibility risk”. Or, at least, to have
an exception made that allows the unsafe marker on
from_outer_unsafe to mean “backwards compatibility risk”, rather
than “memory unsafe”.
source