diff --git a/src/raw/mod.rs b/src/raw/mod.rs index 79eb825..4fc5ac7 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -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 { /// The key for this entry. pub key: K, diff --git a/src/raw/utils/tagged.rs b/src/raw/utils/tagged.rs index 793ebfb..c92de4b 100644 --- a/src/raw/utils/tagged.rs +++ b/src/raw/utils/tagged.rs @@ -1,3 +1,4 @@ +use std::mem::align_of; use std::sync::atomic::{AtomicPtr, Ordering}; // Polyfill for the unstable strict-provenance APIs. @@ -12,9 +13,13 @@ pub unsafe trait StrictProvenance: Sized { } // Unpack a tagged pointer. -pub trait Unpack { +pub trait Unpack: Sized { // A mask for the pointer tag bits. const MASK: usize; + + // This constant, if used, 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 ASSERT_ALIGNMENT: () = assert!(align_of::() > !Self::MASK); } unsafe impl StrictProvenance for *mut T { @@ -33,6 +38,7 @@ unsafe impl StrictProvenance for *mut T { where T: Unpack, { + let () = T::ASSERT_ALIGNMENT; Tagged { raw: self, ptr: self.map_addr(|addr| addr & T::MASK),