@@ -26,9 +26,11 @@ pub(crate) struct ReinterpretedView {
2626pub ( crate ) enum PtrKind < T > {
2727 #[ default]
2828 Null ,
29+ // Variants with the same payload are kept adjacent so that matches on
30+ // Stack*/Heap* pairs compile to range checks rather than jump tables.
2931 StackSingle ( Weak < RefCell < T > > ) ,
30- StackArray ( Weak < RefCell < Box < [ T ] > > > ) ,
3132 HeapSingle ( Weak < RefCell < T > > ) ,
33+ StackArray ( Weak < RefCell < Box < [ T ] > > > ) ,
3234 HeapArray ( Weak < RefCell < Box < [ T ] > > > ) ,
3335 StackVec ( Weak < RefCell < Vec < T > > > ) ,
3436 HeapVec ( Weak < RefCell < Vec < T > > > ) ,
@@ -55,6 +57,9 @@ pub enum StrongPtr<T> {
5557}
5658
5759impl < T : ByteRepr > StrongPtr < T > {
60+ // Inlined together with Ptr::upgrade so that the match on the kind of
61+ // the pointer is folded away.
62+ #[ inline( always) ]
5863 pub fn deref ( & self ) -> Ref < ' _ , T > {
5964 match self {
6065 StrongPtr :: StackSingle ( rc) => rc. borrow ( ) ,
@@ -64,16 +69,23 @@ impl<T: ByteRepr> StrongPtr<T> {
6469 alloc,
6570 byte_offset,
6671 cell,
67- } => {
68- // Read-through: always re-read from the original allocation.
69- with_scratch ( T :: byte_size ( ) , |buf| {
70- alloc. read_bytes ( * byte_offset, buf) ;
71- * cell. borrow_mut ( ) = Some ( T :: from_bytes ( buf) ) ;
72- } ) ;
73- Ref :: map ( cell. borrow ( ) , |opt| opt. as_ref ( ) . unwrap ( ) )
74- }
72+ } => Self :: deref_reinterpreted ( alloc, * byte_offset, cell) ,
7573 }
7674 }
75+
76+ #[ inline( never) ]
77+ fn deref_reinterpreted < ' a > (
78+ alloc : & OriginalAlloc ,
79+ byte_offset : usize ,
80+ cell : & ' a RefCell < Option < T > > ,
81+ ) -> Ref < ' a , T > {
82+ // Read-through: always re-read from the original allocation.
83+ with_scratch ( T :: byte_size ( ) , |buf| {
84+ alloc. read_bytes ( byte_offset, buf) ;
85+ * cell. borrow_mut ( ) = Some ( T :: from_bytes ( buf) ) ;
86+ } ) ;
87+ Ref :: map ( cell. borrow ( ) , |opt| opt. as_ref ( ) . unwrap ( ) )
88+ }
7789}
7890
7991impl < T > fmt:: Debug for PtrKind < T > {
@@ -94,6 +106,7 @@ impl<T> fmt::Debug for PtrKind<T> {
94106}
95107
96108impl < T > Clone for PtrKind < T > {
109+ #[ inline]
97110 fn clone ( & self ) -> Self {
98111 match self {
99112 PtrKind :: Null => PtrKind :: Null ,
@@ -155,6 +168,7 @@ impl<T> Default for Ptr<T> {
155168}
156169
157170impl < T > Clone for Ptr < T > {
171+ #[ inline]
158172 fn clone ( & self ) -> Self {
159173 Self {
160174 offset : self . offset ,
@@ -345,19 +359,19 @@ impl<T> Ptr<T> {
345359 }
346360 }
347361
362+ #[ inline( always) ]
348363 pub fn upgrade ( & self ) -> StrongPtr < T > {
349364 match & self . kind {
350- PtrKind :: Null => panic ! ( "ub: null pointer" ) ,
365+ PtrKind :: Null => null_deref ( ) ,
351366 PtrKind :: StackSingle ( weak) | PtrKind :: HeapSingle ( weak) => {
352- assert_eq ! ( self . offset, 0 , "ub: invalid offset" ) ;
353- StrongPtr :: StackSingle ( weak. upgrade ( ) . expect ( "ub: dangling pointer" ) )
367+ StrongPtr :: StackSingle ( weak. upgrade ( ) . unwrap_or_else ( || dangling ( ) ) )
354368 }
355369 PtrKind :: StackVec ( weak) | PtrKind :: HeapVec ( weak) => StrongPtr :: Vec {
356- rc : weak. upgrade ( ) . expect ( "ub: dangling pointer" ) ,
370+ rc : weak. upgrade ( ) . unwrap_or_else ( || dangling ( ) ) ,
357371 offset : self . offset ,
358372 } ,
359373 PtrKind :: StackArray ( weak) | PtrKind :: HeapArray ( weak) => StrongPtr :: StackArray {
360- rc : weak. upgrade ( ) . expect ( "ub: dangling pointer" ) ,
374+ rc : weak. upgrade ( ) . unwrap_or_else ( || dangling ( ) ) ,
361375 offset : self . offset ,
362376 } ,
363377 PtrKind :: Reinterpreted ( data) => StrongPtr :: Reinterpreted {
@@ -368,6 +382,7 @@ impl<T> Ptr<T> {
368382 }
369383 }
370384
385+ #[ inline( always) ]
371386 pub fn write ( & self , value : T )
372387 where
373388 T : ByteRepr ,
@@ -434,67 +449,101 @@ impl<T> Ptr<T> {
434449}
435450
436451impl < T > Ptr < T > {
452+ #[ inline( always) ]
437453 pub fn with_mut < R > ( & self , f : impl FnOnce ( & mut T ) -> R ) -> R
438454 where
439455 T : ByteRepr ,
440456 {
441457 match & self . kind {
442- PtrKind :: Null => panic ! ( "ub: null pointer" ) ,
443458 PtrKind :: StackSingle ( weak) | PtrKind :: HeapSingle ( weak) => {
444- assert_eq ! ( self . offset, 0 , "ub: invalid offset" ) ;
445- let rc = weak. upgrade ( ) . expect ( "ub: dangling pointer" ) ;
459+ let rc = weak. upgrade ( ) . unwrap_or_else ( || dangling ( ) ) ;
446460 let mut borrow = rc. borrow_mut ( ) ;
447461 f ( & mut * borrow)
448462 }
449- PtrKind :: StackVec ( weak) | PtrKind :: HeapVec ( weak) => {
450- let rc = weak. upgrade ( ) . expect ( "ub: dangling pointer" ) ;
463+ PtrKind :: StackArray ( weak) | PtrKind :: HeapArray ( weak) => {
464+ let rc = weak. upgrade ( ) . unwrap_or_else ( || dangling ( ) ) ;
451465 let mut borrow = rc. borrow_mut ( ) ;
452466 f ( & mut borrow[ self . offset ] )
453467 }
454- PtrKind :: StackArray ( weak) | PtrKind :: HeapArray ( weak) => {
455- let rc = weak. upgrade ( ) . expect ( "ub: dangling pointer" ) ;
468+ PtrKind :: StackVec ( weak) | PtrKind :: HeapVec ( weak) => {
469+ let rc = weak. upgrade ( ) . unwrap_or_else ( || dangling ( ) ) ;
456470 let mut borrow = rc. borrow_mut ( ) ;
457471 f ( & mut borrow[ self . offset ] )
458472 }
459- PtrKind :: Reinterpreted ( data) => with_scratch ( T :: byte_size ( ) , |buf| {
460- data. alloc . read_bytes ( self . offset , buf) ;
461- let mut val = T :: from_bytes ( buf) ;
462- let ret = f ( & mut val) ;
463- val. to_bytes ( buf) ;
464- data. alloc . write_bytes ( self . offset , buf) ;
465- ret
466- } ) ,
473+ PtrKind :: Reinterpreted ( data) => Self :: with_mut_reinterpreted ( data, self . offset , f) ,
474+ PtrKind :: Null => null_deref ( ) ,
467475 }
468476 }
469477
478+ #[ inline( never) ]
479+ fn with_mut_reinterpreted < R > (
480+ data : & ReinterpretedView ,
481+ offset : usize ,
482+ f : impl FnOnce ( & mut T ) -> R ,
483+ ) -> R
484+ where
485+ T : ByteRepr ,
486+ {
487+ with_scratch ( T :: byte_size ( ) , |buf| {
488+ data. alloc . read_bytes ( offset, buf) ;
489+ let mut val = T :: from_bytes ( buf) ;
490+ let ret = f ( & mut val) ;
491+ val. to_bytes ( buf) ;
492+ data. alloc . write_bytes ( offset, buf) ;
493+ ret
494+ } )
495+ }
496+
497+ #[ inline( always) ]
470498 pub fn with < R > ( & self , f : impl FnOnce ( & T ) -> R ) -> R
471499 where
472500 T : ByteRepr ,
473501 {
474502 match & self . kind {
475- PtrKind :: Null => panic ! ( "ub: null pointer" ) ,
476503 PtrKind :: StackSingle ( weak) | PtrKind :: HeapSingle ( weak) => {
477- assert_eq ! ( self . offset, 0 , "ub: invalid offset" ) ;
478- let rc = weak. upgrade ( ) . expect ( "ub: dangling pointer" ) ;
504+ let rc = weak. upgrade ( ) . unwrap_or_else ( || dangling ( ) ) ;
479505 let borrow = rc. borrow ( ) ;
480506 f ( & * borrow)
481507 }
482- PtrKind :: StackVec ( weak) | PtrKind :: HeapVec ( weak) => {
483- let rc = weak. upgrade ( ) . expect ( "ub: dangling pointer" ) ;
508+ PtrKind :: StackArray ( weak) | PtrKind :: HeapArray ( weak) => {
509+ let rc = weak. upgrade ( ) . unwrap_or_else ( || dangling ( ) ) ;
484510 let borrow = rc. borrow ( ) ;
485511 f ( & borrow[ self . offset ] )
486512 }
487- PtrKind :: StackArray ( weak) | PtrKind :: HeapArray ( weak) => {
488- let rc = weak. upgrade ( ) . expect ( "ub: dangling pointer" ) ;
513+ PtrKind :: StackVec ( weak) | PtrKind :: HeapVec ( weak) => {
514+ let rc = weak. upgrade ( ) . unwrap_or_else ( || dangling ( ) ) ;
489515 let borrow = rc. borrow ( ) ;
490516 f ( & borrow[ self . offset ] )
491517 }
492- PtrKind :: Reinterpreted ( data) => with_scratch ( T :: byte_size ( ) , |buf| {
493- data. alloc . read_bytes ( self . offset , buf) ;
494- f ( & T :: from_bytes ( buf) )
495- } ) ,
518+ PtrKind :: Reinterpreted ( data) => Self :: with_reinterpreted ( data, self . offset , f) ,
519+ PtrKind :: Null => null_deref ( ) ,
496520 }
497521 }
522+
523+ #[ inline( never) ]
524+ fn with_reinterpreted < R > ( data : & ReinterpretedView , offset : usize , f : impl FnOnce ( & T ) -> R ) -> R
525+ where
526+ T : ByteRepr ,
527+ {
528+ with_scratch ( T :: byte_size ( ) , |buf| {
529+ data. alloc . read_bytes ( offset, buf) ;
530+ f ( & T :: from_bytes ( buf) )
531+ } )
532+ }
533+ }
534+
535+ #[ cold]
536+ #[ inline( never) ]
537+ #[ track_caller]
538+ fn null_deref ( ) -> ! {
539+ panic ! ( "ub: null pointer" )
540+ }
541+
542+ #[ cold]
543+ #[ inline( never) ]
544+ #[ track_caller]
545+ fn dangling ( ) -> ! {
546+ panic ! ( "ub: dangling pointer" )
498547}
499548
500549impl Ptr < u8 > {
@@ -563,6 +612,7 @@ impl Ptr<u8> {
563612}
564613
565614impl < T : Clone + ByteRepr > Ptr < T > {
615+ #[ inline( always) ]
566616 pub fn read ( & self ) -> T {
567617 self . with ( |v| v. clone ( ) )
568618 }
@@ -1062,6 +1112,40 @@ mod tests {
10621112 p. decay ( ) . delete ( ) ;
10631113 }
10641114
1115+ #[ test]
1116+ #[ should_panic( expected = "ub: dangling pointer" ) ]
1117+ fn read_dangling_panics ( ) {
1118+ let p = {
1119+ let v: Value < i32 > = Rc :: new ( RefCell :: new ( 1 ) ) ;
1120+ v. as_pointer ( )
1121+ } ;
1122+ p. read ( ) ;
1123+ }
1124+
1125+ #[ test]
1126+ #[ should_panic( expected = "ub: dangling pointer" ) ]
1127+ fn write_dangling_array_panics ( ) {
1128+ let p: Ptr < u8 > = Ptr :: alloc_array ( vec ! [ 0u8 ; 4 ] . into_boxed_slice ( ) ) ;
1129+ let q = p. offset ( 1 ) ;
1130+ p. delete ( ) ;
1131+ q. write ( 1 ) ;
1132+ }
1133+
1134+ #[ test]
1135+ fn read_write_through_pointer_to_pointer ( ) {
1136+ let a: Value < Box < [ i32 ] > > = Rc :: new ( RefCell :: new ( vec ! [ 1 , 2 , 3 ] . into_boxed_slice ( ) ) ) ;
1137+ let v: Value < Vec < i32 > > = Rc :: new ( RefCell :: new ( vec ! [ 4 , 5 ] ) ) ;
1138+ let pp: Value < Ptr < i32 > > = Rc :: new ( RefCell :: new ( a. as_pointer ( ) ) ) ;
1139+ let pp_ptr = pp. as_pointer ( ) ;
1140+ pp_ptr. write ( pp_ptr. read ( ) . offset ( 2 ) ) ;
1141+ assert_eq ! ( pp. borrow( ) . read( ) , 3 ) ;
1142+ pp_ptr. read ( ) . write ( 7 ) ;
1143+ assert_eq ! ( a. borrow( ) [ 2 ] , 7 ) ;
1144+ pp_ptr. write ( v. as_pointer ( ) . offset ( 1 ) ) ;
1145+ pp_ptr. read ( ) . write ( 8 ) ;
1146+ assert_eq ! ( * v. borrow( ) , vec![ 4 , 8 ] ) ;
1147+ }
1148+
10651149 #[ test]
10661150 fn reinterpreted_unaligned_access_spans_elements ( ) {
10671151 let p: Ptr < u16 > = Ptr :: alloc_array ( vec ! [ 0u16 ; 4 ] . into_boxed_slice ( ) ) ;
0 commit comments