File tree Expand file tree Collapse file tree 2 files changed +30
-1
lines changed
Expand file tree Collapse file tree 2 files changed +30
-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 @@ -148,4 +148,33 @@ fn max_recycled_cap_respected() {
148148 assert_eq ! ( allocator. heap_size( ) , 0 ) ;
149149 // The recycled list holds exactly max_recycled pages.
150150 assert_eq ! ( allocator. recycled_arenas. len( ) , 4 ) ;
151+ // === test for TaggedPtr::as_ptr === //
152+
153+ // `TaggedPtr::as_ptr` must use `addr & !MASK` to unconditionally clear the high
154+ // bit rather than XORing it out. The XOR approach worked for tagged items
155+ // but incorrectly flipped the bit on untagged items, corrupting the pointer.
156+ #[ test]
157+ fn as_ptr_clears_not_flips_tag_bit ( ) {
158+ let mut allocator = ArenaAllocator :: default ( ) ;
159+
160+ let mut ptr_a = allocator. try_alloc ( 1u64 ) . unwrap ( ) . as_ptr ( ) ;
161+ let mut ptr_b = allocator. try_alloc ( 2u64 ) . unwrap ( ) . as_ptr ( ) ;
162+ let _ptr_c = allocator. try_alloc ( 3u64 ) . unwrap ( ) . as_ptr ( ) ;
163+ assert_eq ! ( allocator. arenas_len( ) , 1 ) ;
164+
165+ // Mark B and C as dropped, leave A live.
166+ unsafe {
167+ ptr_b. as_mut ( ) . mark_dropped ( ) ;
168+ }
169+
170+ let states = allocator. arena_drop_states ( ) ;
171+ assert_eq ! (
172+ states[ 0 ] . as_slice( ) ,
173+ & [ false , true , false ] ,
174+ "item_drop_states must correctly report live/dropped status for all nodes"
175+ ) ;
176+
177+ unsafe {
178+ ptr_a. as_mut ( ) . mark_dropped ( ) ;
179+ }
151180}
You can’t perform that action at this time.
0 commit comments