| Crates.io | unsafe_fn |
| lib.rs | unsafe_fn |
| version | 0.1.2 |
| created_at | 2019-07-20 14:09:13.14635+00 |
| updated_at | 2019-07-22 18:58:39.52749+00 |
| description | macro to mark a function as unsafe without its body being unsafe |
| homepage | |
| repository | https://github.com/ogoffart/unsafe_fn |
| max_upload_size | |
| id | 150346 |
| size | 24,253 |
Attribute macro to mark a function as unsafe without its body being unsafe
Marking a function with the unsafe keywords does two things:
unsafe { ... } block;unsafe
block, so it can perform unsafe code.In many case however, it is not desirable to have the full body
inside an unsafe block.
RFC 2585 discusses that and suggests to no longer treat the body of a unsafe function as unsafe.
In the mean time, this macro allows to declare a unsafe function
with a #[unsafe_fn] attribute, so that the function is unsafe,
but its body is not considered as unsafe.
use unsafe_fn::unsafe_fn;
#[unsafe_fn]
fn add_to_ptr(a_ptr: *const i32, b: i32) -> i32 {
let a = unsafe { *a_ptr }; // dereference in a unsafe block
a + b // safe code outside of the unsafe block
}
let x = &42 as *const i32;
// The function is unsafe and must be called in a unsafe block;
assert_eq!(unsafe { add_to_ptr(x, 1) }, 43);
For consistency, it is also possible to use the unsafe_fn on traits
to declare an unsafe trait
// Equivalent to `unsafe trait UnsafeMarker {}`
#[unsafe_fn] trait UnsafeMarker {}
From the motivation section of RFC 2585:
Marking a function as
unsafeis one of Rust's key protections against undefined behavior: Even if the programmer does not read the documentation, calling anunsafefunction (or performing another unsafe operation) outside an unsafe block will lead to a compile error, hopefully followed by reading the documentation.However, we currently entirely lose this protection when writing an
unsafe fn: If I, say, accidentally call offset instead of wrapping_offset [..] this happens without any further notice when I am writing anunsafe fnbecause the body of anunsafe fnis treated as anunsafeblock.[...]
Using some more formal terminology, an
unsafeblock generally comes with a proof obligation: The programmer has to ensure that this code is actually safe to execute in the current context, because the compiler just trusts the programmer to get this right. In contrast,unsafe fnrepresents an assumption: As the author of this function, I make some assumptions that I expect my callees to uphold.
In general, using an attribute instead of a keyword to mark unsafe function make
sense: the unsafe keyword would mean that the code is unsafe and extra care
need to be used when reviewing this code. While the attribute #[unsafe_fn] merly
declare a function as unsafe, but cannot by itself cause undefined behavior.
Due to a restriction in the way procedural macro works, there are a small limitation:
self nor Self
cannot reference any of the generic type.struct X<T>(T);
impl<T> X<T> {
#[unsafe_fn] // ok: reference self
fn get(&self) -> &T { &self.0 }
// Error! no refernces to 'self' or 'Self', so T cannot be used
#[unsafe_fn]
fn identity(x : &T) -> &T { x }
// error[E0401]: can't use generic parameters from outer function
}
trait Tr {
#[unsafe_fn] fn fn1(&self);
unsafe fn fn2(&self);
}
impl Tr for u32 {
#[unsafe_fn] fn fn1(&self) {} // Ok
#[unsafe_fn] fn fn2(&self) {} // Error: fn2 is not declared with #[unsafe_fn]
// error[E0407]: method `__unsafe_fn_fn2` is not a member of trait `Tr`
}
License: MIT