Skip to content

Commit 0717a8c

Browse files
committed
avoid pointer arithmetic on pool::Box node when handling ZST
1 parent d3be154 commit 0717a8c

File tree

2 files changed

+54
-11
lines changed

2 files changed

+54
-11
lines changed

src/pool/mod.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ use core::{
238238
marker::PhantomData,
239239
mem::MaybeUninit,
240240
ops::{Deref, DerefMut},
241-
ptr,
241+
ptr::{self, NonNull},
242242
};
243243

244244
pub use stack::Node;
@@ -294,6 +294,11 @@ impl<T> Pool<T> {
294294
/// *NOTE:* This method does *not* have bounded execution time because it contains a CAS loop
295295
pub fn alloc(&self) -> Option<Box<T, Uninit>> {
296296
if mem::size_of::<T>() == 0 {
297+
// NOTE because we return a dangling pointer to a NODE, which has non-zero size
298+
// even when T is a ZST, in this case we need to make sure we
299+
// - don't do pointer arithmetic on this pointer
300+
// - dereference that offset-ed pointer as a ZST
301+
// because miri doesn't like that
297302
return Some(Box {
298303
node: Ptr::dangling(),
299304
_state: PhantomData,
@@ -320,8 +325,14 @@ impl<T> Pool<T> {
320325
S: 'static,
321326
{
322327
if TypeId::of::<S>() == TypeId::of::<Init>() {
328+
let p = if mem::size_of::<T>() == 0 {
329+
// any pointer will do to invoke the destructor of a ZST
330+
NonNull::dangling().as_ptr()
331+
} else {
332+
unsafe { value.node.as_ref().data.get() }
333+
};
323334
unsafe {
324-
ptr::drop_in_place(value.node.as_ref().data.get());
335+
ptr::drop_in_place(p);
325336
}
326337
}
327338

@@ -428,8 +439,14 @@ pub struct Box<T, STATE = Init> {
428439
impl<T> Box<T, Uninit> {
429440
/// Initializes this memory block
430441
pub fn init(self, val: T) -> Box<T, Init> {
431-
unsafe {
432-
ptr::write(self.node.as_ref().data.get(), val);
442+
if mem::size_of::<T>() == 0 {
443+
// no memory operation needed for ZST
444+
// BUT we want to avoid calling `val`s destructor
445+
mem::forget(val)
446+
} else {
447+
unsafe {
448+
ptr::write(self.node.as_ref().data.get(), val);
449+
}
433450
}
434451

435452
Box {
@@ -473,13 +490,23 @@ impl<T> Deref for Box<T> {
473490
type Target = T;
474491

475492
fn deref(&self) -> &T {
476-
unsafe { &*self.node.as_ref().data.get() }
493+
if mem::size_of::<T>() == 0 {
494+
// any pointer will do for ZST
495+
unsafe { &*NonNull::dangling().as_ptr() }
496+
} else {
497+
unsafe { &*self.node.as_ref().data.get() }
498+
}
477499
}
478500
}
479501

480502
impl<T> DerefMut for Box<T> {
481503
fn deref_mut(&mut self) -> &mut T {
482-
unsafe { &mut *self.node.as_ref().data.get() }
504+
if mem::size_of::<T>() == 0 {
505+
// any pointer will do for ZST
506+
unsafe { &mut *NonNull::dangling().as_ptr() }
507+
} else {
508+
unsafe { &mut *self.node.as_ref().data.get() }
509+
}
483510
}
484511
}
485512

src/pool/singleton.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use core::{
77
marker::PhantomData,
88
mem::{self, MaybeUninit},
99
ops::{Deref, DerefMut},
10-
ptr,
10+
ptr::{self, NonNull},
1111
};
1212

1313
use super::{Init, Node, Uninit};
@@ -109,8 +109,14 @@ where
109109

110110
mem::forget(self);
111111

112-
unsafe {
113-
ptr::write(node.as_ref().data.get(), val);
112+
if mem::size_of::<P::Data>() == 0 {
113+
// no memory operation needed for ZST
114+
// BUT we want to avoid calling `val`s destructor
115+
mem::forget(val)
116+
} else {
117+
unsafe {
118+
ptr::write(node.as_ref().data.get(), val);
119+
}
114120
}
115121

116122
Box {
@@ -167,7 +173,11 @@ where
167173
let node = self.inner.node;
168174

169175
mem::forget(self);
170-
mem::forget(unsafe { ptr::read(node.as_ref().data.get()) });
176+
if mem::size_of::<P::Data>() == 0 {
177+
// no need to do a pointer dereference in this case
178+
} else {
179+
mem::forget(unsafe { ptr::read(node.as_ref().data.get()) });
180+
}
171181

172182
Box {
173183
inner: super::Box {
@@ -228,8 +238,14 @@ where
228238
{
229239
fn drop(&mut self) {
230240
if TypeId::of::<S>() == TypeId::of::<Init>() {
241+
let p = if mem::size_of::<P::Data>() == 0 {
242+
// any pointer will do to invoke the destructor of a ZST
243+
NonNull::dangling().as_ptr()
244+
} else {
245+
unsafe { self.inner.node.as_ref().data.get() }
246+
};
231247
unsafe {
232-
ptr::drop_in_place(self.inner.node.as_ref().data.get());
248+
ptr::drop_in_place(p);
233249
}
234250
}
235251

0 commit comments

Comments
 (0)