Skip to content

Commit

Permalink
Auto merge of #390 - RalfJung:strict-provenance, r=Amanieu
Browse files Browse the repository at this point in the history
use strict provenance APIs on nightly

This makes hashbrown compatible with strict provenance, which helps Miri in ensuring pointers are used correctly.

Fixes #384
  • Loading branch information
bors committed Mar 24, 2023
2 parents a2de204 + dd6aceb commit ae3e67b
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 5 deletions.
2 changes: 1 addition & 1 deletion ci/miri.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ rustup toolchain install nightly --component miri
rustup override set nightly
cargo miri setup

MIRIFLAGS='-Zmiri-retag-fields' cargo miri test
MIRIFLAGS='-Zmiri-strict-provenance' cargo miri test --features nightly
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
slice_ptr_get,
nonnull_slice_from_raw_parts,
maybe_uninit_array_assume_init,
build_hasher_simple_hash_one
build_hasher_simple_hash_one,
strict_provenance
)
)]
#![allow(
Expand All @@ -37,6 +38,7 @@
)]
#![warn(missing_docs)]
#![warn(rust_2018_idioms)]
#![cfg_attr(feature = "nightly", warn(fuzzy_provenance_casts))]

#[cfg(test)]
#[macro_use]
Expand Down
18 changes: 15 additions & 3 deletions src/raw/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ fn unlikely(b: bool) -> bool {
b
}

// Use strict provenance functions if available.
#[cfg(feature = "nightly")]
use core::ptr::invalid_mut;
// Implement it with a cast otherwise.
#[cfg(not(feature = "nightly"))]
#[inline(always)]
fn invalid_mut<T>(addr: usize) -> *mut T {
addr as *mut T
}

#[inline]
unsafe fn offset_from<T>(to: *const T, from: *const T) -> usize {
to.offset_from(from) as usize
Expand Down Expand Up @@ -371,7 +381,7 @@ impl<T> Bucket<T> {
// won't overflow because index must be less than length (bucket_mask)
// and bucket_mask is guaranteed to be less than `isize::MAX`
// (see TableLayout::calculate_layout_for method)
(index + 1) as *mut T
invalid_mut(index + 1)
} else {
base.as_ptr().sub(index)
};
Expand Down Expand Up @@ -507,7 +517,8 @@ impl<T> Bucket<T> {
pub fn as_ptr(&self) -> *mut T {
if Self::IS_ZERO_SIZED_TYPE {
// Just return an arbitrary ZST pointer which is properly aligned
mem::align_of::<T>() as *mut T
// invalid pointer is good enough for ZST
invalid_mut(mem::align_of::<T>())
} else {
unsafe { self.ptr.as_ptr().sub(1) }
}
Expand Down Expand Up @@ -553,7 +564,8 @@ impl<T> Bucket<T> {
#[inline]
unsafe fn next_n(&self, offset: usize) -> Self {
let ptr = if Self::IS_ZERO_SIZED_TYPE {
(self.ptr.as_ptr() as usize + offset) as *mut T
// invalid pointer is good enough for ZST
invalid_mut(self.ptr.as_ptr() as usize + offset)
} else {
self.ptr.as_ptr().sub(offset)
};
Expand Down
7 changes: 7 additions & 0 deletions src/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2907,4 +2907,11 @@ mod test_set {
set.insert(i);
}
}

#[test]
fn collect() {
// At the time of writing, this hits the ZST case in from_base_index
// (and without the `map`, it does not).
let mut _set: HashSet<_> = (0..3).map(|_| ()).collect();
}
}

0 comments on commit ae3e67b

Please sign in to comment.