File tree Expand file tree Collapse file tree 2 files changed +32
-1
lines changed
Expand file tree Collapse file tree 2 files changed +32
-1
lines changed Original file line number Diff line number Diff line change @@ -115,7 +115,7 @@ impl<T> TaggedPtr<T> {
115115 }
116116
117117 fn as_ptr ( & self ) -> * mut T {
118- self . 0 . map_addr ( |addr| addr ^ MASK )
118+ self . 0 . map_addr ( |addr| addr & ! MASK )
119119 }
120120}
121121
Original file line number Diff line number Diff line change @@ -88,3 +88,34 @@ fn arc_drop() {
8888
8989 assert_eq ! ( allocator. arenas_len( ) , 0 ) ;
9090}
91+
92+ // === test for TaggedPtr::as_ptr === //
93+
94+ // `TaggedPtr::as_ptr` must use `addr & !MASK` to unconditionally clear the high
95+ // bit rather than XORing it out. The XOR approach worked for tagged items
96+ // but incorrectly flipped the bit on untagged items, corrupting the pointer.
97+ #[ test]
98+ fn as_ptr_clears_not_flips_tag_bit ( ) {
99+ let mut allocator = ArenaAllocator :: default ( ) ;
100+
101+ let mut ptr_a = allocator. try_alloc ( 1u64 ) . unwrap ( ) . as_ptr ( ) ;
102+ let mut ptr_b = allocator. try_alloc ( 2u64 ) . unwrap ( ) . as_ptr ( ) ;
103+ let _ptr_c = allocator. try_alloc ( 3u64 ) . unwrap ( ) . as_ptr ( ) ;
104+ assert_eq ! ( allocator. arenas_len( ) , 1 ) ;
105+
106+ // Mark B and C as dropped, leave A live.
107+ unsafe {
108+ ptr_b. as_mut ( ) . mark_dropped ( ) ;
109+ }
110+
111+ let states = allocator. arena_drop_states ( ) ;
112+ assert_eq ! (
113+ states[ 0 ] . as_slice( ) ,
114+ & [ false , true , false ] ,
115+ "item_drop_states must correctly report live/dropped status for all nodes"
116+ ) ;
117+
118+ unsafe {
119+ ptr_a. as_mut ( ) . mark_dropped ( ) ;
120+ }
121+ }
You can’t perform that action at this time.
0 commit comments