From bbc7b857fc9f349c1ad0a80965d6e3f2d758ecff Mon Sep 17 00:00:00 2001 From: mrhapile Date: Thu, 5 Mar 2026 18:45:37 +0530 Subject: [PATCH] Prevent root_count overflow in GcHeader Signed-off-by: mrhapile --- .../mark_sweep/internals/gc_header.rs | 21 +++++++++++++++++-- oscars/src/collectors/mark_sweep/tests.rs | 3 +++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/oscars/src/collectors/mark_sweep/internals/gc_header.rs b/oscars/src/collectors/mark_sweep/internals/gc_header.rs index a163ca7..506fa3e 100644 --- a/oscars/src/collectors/mark_sweep/internals/gc_header.rs +++ b/oscars/src/collectors/mark_sweep/internals/gc_header.rs @@ -100,8 +100,15 @@ impl GcHeader { } pub fn inc_roots(&self) { - // NOTE: This may panic or overflow after 2^16 - 1 roots - self.root_count.set(self.root_count.get() + 1); + // Prevent silent overflow of root_count. + // In release builds, `u16::MAX + 1` would wrap to 0 and break GC invariants, + // potentially allowing live objects to be collected incorrectly. + let current = self.root_count.get(); + let new = current + .checked_add(1) + .expect("GcHeader root_count overflow"); + + self.root_count.set(new); } pub fn dec_roots(&self) { @@ -170,4 +177,14 @@ mod tests { assert!(!header.is_white(), "failed to toggle black"); assert!(!header.is_grey(), "failed to toggle black"); } + + #[test] + #[should_panic(expected = "GcHeader root_count overflow")] + fn root_count_overflow_panics() { + let header = GcHeader::new_white(); + + for _ in 0..=u16::MAX { + header.inc_roots(); + } + } } diff --git a/oscars/src/collectors/mark_sweep/tests.rs b/oscars/src/collectors/mark_sweep/tests.rs index 2e4b7e2..5f654d1 100644 --- a/oscars/src/collectors/mark_sweep/tests.rs +++ b/oscars/src/collectors/mark_sweep/tests.rs @@ -1,3 +1,6 @@ +#[cfg(feature = "std")] +extern crate std; + use crate::collectors::mark_sweep::MarkSweepGarbageCollector; use crate::{Finalize, Trace};