The full proposal document is in our tag-std repository. It's too long to read in this post, considering there are more conversations going on.
We are experimenting this feature on verify-rust-std, Rust for Linux, and Asterinas OS.
Any idea and feedback is welcome!
Summary
This RFC proposes a DSL (domain-specific language)-based mechanism for specifying safety properties, aiming to standardize how safety descriptions are written in API documentation. On the one hand, it seeks to improve the ergonomics of writing safety descriptions; on the other hand, these safety properties can enable finer-grained unsafe code management and automated safety checking.
This RFC operates at the API level rather than the compiler or language level, as it merely introduces attribute macros on functions and expressions that are already expressible today, but may require a linter tool to realize automated check.
This RFC has influences on the entire crate ecosystem, including the standard library and downstream crates.
Demo
Ensure safety requirements are never missing
fn try_fold<B, F, R>(&mut self, mut init: B, mut f: F) -> R {
...
init = head.iter().map(|elem| {
guard.consumed += 1;
#[safety::discharges::ValidPtr(elem, T, 1)]
#[safety::discharges::Aligned(elem, T)]
#[safety::discharges::Init(elem, T, 1)]
#[safety::discharges::NotOwned(elem, memo = "
Because we incremented `guard.consumed`, the deque
effectively forgot the element, so we can take ownership.
")]
#[safety::discharges::Alias(elem, head.iter())]
unsafe { ptr::read(elem) }
})
.try_fold(init, &mut f)?;
...
}
Update: we will make the syntax less verbose, like this
#[safety { ValidPtr(ptr) }] // defsite: add SP on this API
unsafe fn raw_get_work(ptr: *mut Self) -> *mut Work<T, ID> {
let ptr = ptr as *mut u8;
#[safety { InBound, ValidNum }] // callsite: discharge SP
unsafe { ptr.add(Self::OFFSET).cast() }
}
see Pre-RFC: Safety Property System - #23 by vague
