Skip to content

Commit 8693c13

Browse files
committed
feat: support strict provenance and use it for fat pointer coercion
1 parent 6068088 commit 8693c13

File tree

4 files changed

+56
-24
lines changed

4 files changed

+56
-24
lines changed

src/cc.rs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ pub type Cc<T> = RawCc<T, ObjectSpace>;
7878
pub type Weak<T> = RawWeak<T, ObjectSpace>;
7979

8080
/// Low-level type for [`Cc<T>`](type.Cc.html).
81+
#[repr(transparent)]
8182
pub struct RawCc<T: ?Sized, O: AbstractObjectSpace>(NonNull<RawCcBox<T, O>>);
8283

8384
/// Low-level type for [`Weak<T>`](type.Weak.html).
@@ -225,9 +226,8 @@ impl<T: Trace, O: AbstractObjectSpace> RawCc<T, O> {
225226
// Cc<dyn Trace> has 2 usize values: The first one is the same
226227
// as Cc<T>. The second one is the vtable. The vtable pointer
227228
// is the same as the second pointer of `&dyn Trace`.
228-
let mut fat_ptr: [usize; 2] = mem::transmute(self.inner().deref() as &dyn Trace);
229-
let self_ptr: usize = mem::transmute(self);
230-
fat_ptr[0] = self_ptr;
229+
let fat_ptr: *const dyn Trace = &**self.inner();
230+
let fat_ptr = fat_ptr.with_addr(mem::transmute::<RawCc<T, O>, usize>(self));
231231
mem::transmute(fat_ptr)
232232
}
233233
}
@@ -236,11 +236,15 @@ impl<T: Trace, O: AbstractObjectSpace> RawCc<T, O> {
236236
/// Create Cc<dyn Trait> from Cc<T> where T: impl Trait, Trait is trait object
237237
#[macro_export]
238238
macro_rules! cc_dyn {
239-
($(#[$($meta:meta)+])* $conv:ident, $t:path $(, $new_vis:vis fn new() {...})?) => {
239+
(
240+
$(#[$($meta:meta)+])*
241+
$conv:ident $(<$($gen:ident $(: $($gen_bound:path),+)?),+>)?,
242+
$t:path $(, $new_vis:vis fn new() {...})?
243+
) => {
240244
$(#[$($meta)+])*
241245
#[repr(transparent)]
242-
pub struct $conv($crate::Cc<dyn $t>);
243-
impl $crate::Trace for $conv {
246+
pub struct $conv$(<$($gen),+>)?($crate::Cc<dyn $t>);
247+
impl$(<$($gen: 'static),+>)? $crate::Trace for $conv$(<$($gen),+>)? {
244248
fn trace(&self, tracer: &mut $crate::Tracer) {
245249
$crate::Cc::<dyn $t>::trace(&self.0, tracer)
246250
}
@@ -250,17 +254,14 @@ macro_rules! cc_dyn {
250254
true
251255
}
252256
}
253-
impl $conv {
257+
impl$(<$($gen $(: $($gen_bound),+)?),+>)? $conv$(<$($gen),+>)? {
254258
$($new_vis)? fn new<T: $t + $crate::Trace>(input: T) -> Self {
255-
use std::ops::Deref;
256-
unsafe {
257-
let cc: $crate::RawCc<_, _> = $crate::Cc::new(input);
258-
let mut fat_ptr: [usize; 2] =
259-
core::mem::transmute(cc.inner().deref() as &dyn $t);
260-
let self_ptr: usize = core::mem::transmute(cc);
261-
fat_ptr[0] = self_ptr;
262-
$conv(core::mem::transmute::<[usize; 2], $crate::RawCc<dyn $t, _>>(fat_ptr))
263-
}
259+
let cc: $crate::RawCc<_, _> = $crate::Cc::new(input);
260+
let ptr: *const dyn $t = &**cc.inner();
261+
let ptr = unsafe {
262+
ptr.with_addr(core::mem::transmute::<$crate::RawCc<T, _>, usize>(cc))
263+
};
264+
$conv(unsafe {core::mem::transmute::<*const dyn $t, $crate::RawCc<dyn $t, _>>(ptr)})
264265
}
265266
}
266267
};

src/collect.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ const PREV_SHIFT: u32 = 2;
293293

294294
#[inline]
295295
fn unmask_ptr<T>(ptr: *const T) -> *const T {
296-
((ptr as usize) & PTR_MASK) as *const T
296+
ptr.map_addr(|ptr| ptr & PTR_MASK)
297297
}
298298

299299
/// Temporarily use `GcHeader.prev` as `gc_ref_count`.

src/lib.rs

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -379,11 +379,10 @@ pub mod interop {
379379

380380
#[cfg(test)]
381381
mod dyn_cc {
382-
use crate::Trace;
382+
use crate::{dyn_cc, Trace};
383383
use std::fmt::Debug;
384-
use std::ops::Deref;
385384

386-
use crate::{cc_dyn, Cc};
385+
use crate::cc_dyn;
387386

388387
#[derive(Debug, Trace)]
389388
struct Test {
@@ -392,25 +391,56 @@ mod dyn_cc {
392391

393392
trait DebugAndTrace: Debug + Trace {}
394393
impl<T> DebugAndTrace for T where T: Debug + Trace {}
395-
cc_dyn!(CcDebugAndTrace, DebugAndTrace);
394+
cc_dyn!(
395+
#[derive(Debug)]
396+
CcDebugAndTrace,
397+
DebugAndTrace
398+
);
399+
400+
trait BorrowTy<O> {
401+
fn borrow_ty(&self) -> &O;
402+
}
403+
cc_dyn!(CcBorrowTy<O>, BorrowTy<O>);
404+
cc_dyn!(
405+
CcBorrowTyAlsoDebug<O: Debug>,
406+
BorrowTy<O>
407+
);
408+
409+
#[derive(Trace)]
410+
struct Borrowable<T: Trace> {
411+
v: T,
412+
}
413+
impl<T: Trace> BorrowTy<T> for Borrowable<T> {
414+
fn borrow_ty(&self) -> &T {
415+
&self.v
416+
}
417+
}
396418

397419
#[test]
398420
fn test_dyn() {
399421
let test = Test {
400422
a: "hello".to_owned(),
401423
};
402424

425+
let dynccgeneric = CcBorrowTy::new(Borrowable { v: 1u32 });
426+
let v = dynccgeneric.0.borrow_ty();
427+
assert_eq!(*v, 1);
428+
429+
let dynccgeneric = CcBorrowTyAlsoDebug::new(Borrowable { v: 1u32 });
430+
let v = dynccgeneric.0.borrow_ty();
431+
assert_eq!(*v, 1);
432+
403433
let dyncc = CcDebugAndTrace::new(test);
404-
assert_eq!(format!("{dyncc:?}"), "Cc(Test { a: \"hello\" })");
434+
assert_eq!(format!("{dyncc:?}"), "CcDebugAndTrace(Cc(Test { a: \"hello\" }))");
405435
let dyncc_is_trace = dyncc;
406436
assert_eq!(
407437
format!("{dyncc_is_trace:?}"),
408-
"Cc(Cc(Test { a: \"hello\" }))"
438+
"CcDebugAndTrace(Cc(Test { a: \"hello\" }))"
409439
);
410440
let dyncc_is_trace_as_dyn = CcDebugAndTrace::new(dyncc_is_trace);
411441
assert_eq!(
412442
format!("{dyncc_is_trace_as_dyn:?}"),
413-
"Cc(Cc(Test { a: \"hello\" }))"
443+
"CcDebugAndTrace(Cc(CcDebugAndTrace(Cc(Test { a: \"hello\" }))))"
414444
);
415445
}
416446
}

src/ref_count.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub trait RefCount: 'static {
4040
fn weak_count(&self) -> usize;
4141
}
4242

43+
#[repr(C)]
4344
pub struct SingleThreadRefCount(Cell<usize>, Cell<usize>);
4445

4546
impl SingleThreadRefCount {

0 commit comments

Comments
 (0)