Skip to content

Commit 2a0eae6

Browse files
authored
Merge branch 'main' into recycle
2 parents 656223f + f37d70e commit 2a0eae6

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

oscars/src/alloc/arena2/alloc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff 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

oscars/src/alloc/arena2/tests.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff 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
}

0 commit comments

Comments
 (0)