[T]::split_at_mut
Vec<T>
growingWhat does this program print?
5.88545e-44
Accesses past the end of an array are undefined behavior
Why not simply define what happens on an out-of-bounds memory access?
operator[]
in Rust requires bounds checking
unsafe
Rustunsafe
keywordunsafe
function, we need an unsafe {}
blockunsafe {}
blocks with a //SAFETY
comment!unsafe
is dangerousunsafe fn
will have safety guarantees: Rules that you have to follow in order to make it safe to use this functionunsafe
unsafe
? (1/4)Calling a C function:
unsafe
? (2/4)Accessing a non-existing element in a HashMap
:
unsafe
? (3/4)Allocating a block of memory on the heap:
unsafe
? (4/4)Accessing a mutable global variable:
unsafe
code*const T
and *mut T
std::ptr
module
The precise rules for validity are not determined yet
0
or 1
for a bool
, nothing else)*
ptr::read
ptr::write
Let’s implement Vec<T>
:)
Vec<T>
v1Box<[T]>
?Vec<T>
v2unsafe
:
fn push_first(&mut self, element: T) {
const INITIAL_CAPACITY: usize = 4;
let layout = Layout::array::<T>(INITIAL_CAPACITY)
.expect("Failed to allocate new dynamic array");
// SAFETY: We check for null afterwards
let arr: *mut T = unsafe { std::alloc::alloc(layout) as *mut T };
// alloc is allowed to return a null-pointer if there is not enough memory
if arr.is_null() {
panic!("Out of memory");
}
let first = arr.add(0); // For clarity
// SAFETY: Layout matches `T`
unsafe {
first.write(element); // This 'forgets' the old value
}
self.length += 1;
self.ptr = arr;
self.capacity = INITIAL_CAPACITY;
}
Drop
for Vec<T>
is important
Vec<T>
(how?)impl<T> Drop for Vec<T> {
fn drop(&mut self) {
if self.ptr.is_null() {
return;
}
for idx in 0..self.length {
// SAFETY: Element is properly initialized
let element = unsafe { self.ptr.add(index).read() };
drop(element);
}
let layout = Layout::array::<T>(self.capacity)
.expect("Invalid Layout");
// SAFETY: ptr is not null and the Layout matches
unsafe {
dealloc(self.ptr as *const u8, layout);
}
}
}
unsafe
code to be safe for all possible usage patterns
unsafe
code can be made sound by preventing invalid usageVec<T>
in the standard library uses tons of unsafe
code, but has a safe and easy-to-use API