Skip to content

Commit

Permalink
Fix OOB get_unchecked, shadow Vec::as_ptr methods
Browse files Browse the repository at this point in the history
The tweaks in rust-embedded#280 missed one instance of UB. The get_unchecked_mut
inside VacantEntry::Insert can be out of bounds of the initialized
region of the backing Vec. When that happens, the call is UB. This is
detected both by the standard library's debug assertions which can be
enabled with -Zbuild-std and with Miri but only with
-Zmiri-tag-raw-pointers.

This also adds inherent as_ptr and as_mut_ptr methods to Vec which
shadow those provided by the Deref to a slice. Without this shadowing,
this change doesn't actually fix the problem identified by the debug
assertions or Miri, it just hides it from the debug assertions. The core
problem is that references narrow provenance, so if we want to access
outside of the initialized region of a Vec we need to get a pointer to
the array without passing through a reference to the initialized region
first. The pointers from these shadowing methods can be used to access
anywhere in the allocation, whereas vec.as_slice().as_ptr() would be UB
to use for access into the uninitialized region.
  • Loading branch information
saethlin committed Jun 18, 2022
1 parent 309f150 commit 23c6de1
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/indexmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ where
unsafe {
// SAFETY: Already checked existence at instantiation and the only mutable reference
// to the map is internally held.
Ok(&mut self.core.entries.get_unchecked_mut(inserted.index).value)
Ok(&mut (*self.core.entries.as_mut_ptr().add(inserted.index)).value)
}
}
Insert::Full((_, v)) => Err(v),
Expand Down
10 changes: 10 additions & 0 deletions src/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,16 @@ impl<T, const N: usize> Vec<T, N> {
new
}

/// Returns a raw pointer to the vector’s buffer.
pub fn as_ptr(&self) -> *const T {
self.buffer.as_ptr() as *const T
}

/// Returns a raw pointer to the vector’s buffer, which may be mutated through.
pub fn as_mut_ptr(&mut self) -> *mut T {
self.buffer.as_mut_ptr() as *mut T
}

/// Extracts a slice containing the entire vector.
///
/// Equivalent to `&s[..]`.
Expand Down

0 comments on commit 23c6de1

Please sign in to comment.