Skip to content

Commit 270db44

Browse files
committed
Fix OOB get_unchecked, shadow Vec::as_ptr methods
The fixes 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, the change from get_unchecked_mut to as_mut_ptr.add wouldn'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.
1 parent 309f150 commit 270db44

File tree

2 files changed

+11
-1
lines changed

2 files changed

+11
-1
lines changed

src/indexmap.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ where
416416
unsafe {
417417
// SAFETY: Already checked existence at instantiation and the only mutable reference
418418
// to the map is internally held.
419-
Ok(&mut self.core.entries.get_unchecked_mut(inserted.index).value)
419+
Ok(&mut (*self.core.entries.as_mut_ptr().add(inserted.index)).value)
420420
}
421421
}
422422
Insert::Full((_, v)) => Err(v),

src/vec.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ impl<T, const N: usize> Vec<T, N> {
107107
new
108108
}
109109

110+
/// Returns a raw pointer to the vector’s buffer.
111+
pub fn as_ptr(&self) -> *const T {
112+
self.buffer.as_ptr() as *const T
113+
}
114+
115+
/// Returns a raw pointer to the vector’s buffer, which may be mutated through.
116+
pub fn as_mut_ptr(&mut self) -> *mut T {
117+
self.buffer.as_mut_ptr() as *mut T
118+
}
119+
110120
/// Extracts a slice containing the entire vector.
111121
///
112122
/// Equivalent to `&s[..]`.

0 commit comments

Comments
 (0)