Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/raw/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,9 @@ pub enum RawInsertResult<'g, K, V> {
},
}

// An entry in the hash-table.
#[repr(C)]
// An entry in the hash-table. We force a minimum of 8-byte alignment because
// we store entry flags in the low 3 bits of pointers to this type.
#[repr(C, align(8))]
pub struct Entry<K, V> {
/// The key for this entry.
pub key: K,
Expand Down
12 changes: 12 additions & 0 deletions src/raw/utils/tagged.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::mem::align_of;
use std::sync::atomic::{AtomicPtr, Ordering};

// Polyfill for the unstable strict-provenance APIs.
Expand All @@ -17,6 +18,16 @@ pub trait Unpack {
const MASK: usize;
}

// This function does nothing, but will fail to compile if T doesn't have an alignment
// that guarantees all valid pointers have zero in the bits excluded by T::MASK.
const fn static_assert_align_of<T: Unpack>() {
struct Dummy<T>(T);
impl<T: Unpack> Dummy<T> {
const ASSERT: () = assert!(align_of::<T>() > !T::MASK);
Copy link
Copy Markdown
Owner

@ibraheemdev ibraheemdev Jun 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a bit, can we put this const in the Unpack trait to avoid the dummy struct?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, just pushed.

I didn't do that originally since a trait can only supply a "default" implementation, so an impl could in theory override it with e.g. const ASSERT_ALIGNMENT: () = (); and defeat the check. But I don't think that's going to happen by accident!

}
Dummy::<T>::ASSERT
}

unsafe impl<T> StrictProvenance<T> for *mut T {
#[inline(always)]
fn addr(self) -> usize {
Expand All @@ -33,6 +44,7 @@ unsafe impl<T> StrictProvenance<T> for *mut T {
where
T: Unpack,
{
static_assert_align_of::<T>();
Tagged {
raw: self,
ptr: self.map_addr(|addr| addr & T::MASK),
Expand Down