Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion oscars/src/alloc/arena2/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl<T> TaggedPtr<T> {
}

fn as_ptr(&self) -> *mut T {
self.0.map_addr(|addr| addr ^ MASK)
self.0.map_addr(|addr| addr & !MASK)
}
}

Expand Down
31 changes: 31 additions & 0 deletions oscars/src/alloc/arena2/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,34 @@ fn arc_drop() {

assert_eq!(allocator.arenas_len(), 0);
}

// === test for TaggedPtr::as_ptr === //

// `TaggedPtr::as_ptr` must use `addr & !MASK` to unconditionally clear the high
// bit rather than XORing it out. The XOR approach worked for tagged items
// but incorrectly flipped the bit on untagged items, corrupting the pointer.
#[test]
fn as_ptr_clears_not_flips_tag_bit() {
let mut allocator = ArenaAllocator::default();

let mut ptr_a = allocator.try_alloc(1u64).unwrap().as_ptr();
let mut ptr_b = allocator.try_alloc(2u64).unwrap().as_ptr();
let _ptr_c = allocator.try_alloc(3u64).unwrap().as_ptr();
assert_eq!(allocator.arenas_len(), 1);

// Mark B and C as dropped, leave A live.
unsafe {
ptr_b.as_mut().mark_dropped();
}

let states = allocator.arena_drop_states();
assert_eq!(
states[0].as_slice(),
&[false, true, false],
"item_drop_states must correctly report live/dropped status for all nodes"
);

unsafe {
ptr_a.as_mut().mark_dropped();
}
}
Loading