[API] Implement missing Gc API in branded collector - #98
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fills out the branded collectors’ Gc API surface to better match the unbranded collectors, including pointer utilities and downcasting support, and updates existing tests to use Deref rather than a dedicated get() method.
Changes:
- Added missing
GcAPIs (ptr_eq,is,cast_unchecked,into_raw/from_raw,AsRef,Default) and renamedGc::gettoinner_ref. - Extended
GcBoxheaders with a stored runtime type descriptor to supportGc::iswithout requiring'static. - Relaxed
PoolPointer::from_rawto supportT: ?Sizedand updated branded mark/sweep tests accordingly.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| oscars/src/collectors/null_collector_branded/mutation_ctx.rs | Adds a global() accessor for a thread-local collector-backed mutation context. |
| oscars/src/collectors/null_collector_branded/gc.rs | Adds pointer helpers, raw conversions, is, AsRef, and Default; renames get → inner_ref. |
| oscars/src/collectors/null_collector_branded/gc_box.rs | Stores a type descriptor in GcBox to support Gc::is. |
| oscars/src/collectors/mark_sweep_branded/mutation_ctx.rs | Adds a global() accessor for a thread-local collector-backed mutation context. |
| oscars/src/collectors/mark_sweep_branded/gc.rs | Adds pointer helpers, raw conversions, is, AsRef, and Default; renames get → inner_ref. |
| oscars/src/collectors/mark_sweep_branded/gc_box.rs | Stores a type descriptor in GcBox to support Gc::is. |
| oscars/src/collectors/mark_sweep_branded/tests/mod.rs | Updates tests to use Deref access instead of gc.get(). |
| oscars/src/collectors/mark_sweep_branded/tests/ephemeron.rs | Updates tests to use Deref access instead of val.get(). |
| oscars/src/alloc/mempool3/alloc.rs | Makes PoolPointer::from_raw accept T: ?Sized to support new branded APIs. |
Suppressed comments (2)
oscars/src/collectors/mark_sweep_branded/gc.rs:117
- This
Defaultimpl allocates viaMutationContext::global(), which allows constructingGc<'gc, T>outside aGcContext::mutatewindow. That defeats the whole purpose of the branded'gclifetime and makes it possible to keep aGcalive across acollect()call, reintroducing the use-after-free scenario thattests/uaf.rsis explicitly designed to prevent.
impl<'gc, T: Trace + Finalize + Default + 'gc> Default for Gc<'gc, T> {
fn default() -> Self {
crate::collectors::mark_sweep_branded::MutationContext::global()
.try_alloc(Default::default())
.unwrap()
oscars/src/collectors/null_collector_branded/gc.rs:114
- This
Defaultimpl allocates from a thread-local global collector, which allows producingGc<'gc, T>values that can be treated as long-lived (potentially'static). Since the underlying collector is thread-local and is dropped at thread exit, aGcthat escapes the thread can become dangling and lead to use-after-free.
impl<'gc, T: Trace + Finalize + Default + 'gc> Default for Gc<'gc, T> {
fn default() -> Self {
crate::collectors::null_collector_branded::MutationContext::global()
.try_alloc(Default::default())
.unwrap()
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| #[inline] | ||
| pub fn is<U: Trace + ?Sized + 'gc>(&self) -> bool { | ||
| let actual_type_name = unsafe { (*self.ptr.as_ptr().as_ptr()).0.type_name }; | ||
| actual_type_name == core::any::type_name::<U>() | ||
| } |
There was a problem hiding this comment.
Wait, this is a completely valid concern. If two types have the same name but don't have the same structure, this would cause immediate UB. Why can't we use TypeId here?
There was a problem hiding this comment.
Oh! completely slipped out of my mind. I had this marked as a future todo, but completely forgot about it. Yes this a completely valid concern. On it, opening a PR for this right now
7bae8c1 to
0948ed9
Compare
e1cba1e to
b218a82
Compare
Implemented ptr_eq, is, cast_unchecked, from_raw, into_raw, AsRef and Default for Gc in mark_sweep_branded and null_collector_branded Added type_name to GcBox allocation to support downcasting via Gc::is without 'static lifetime bounds Renamed Gc::get method to inner_ref to avoid shadowing Deref trait methods Allowed DST keys in Ephemeron methods Used core::ptr instead of std::ptr for no_std compatibility
fe907d5 to
f78dd5f
Compare
Top of the stack (#98 -> #97 -> #96)
ptr_eq,is,cast_unchecked,from_raw,into_raw,AsRefandDefaultforGcinmark_sweep_brandedandnull_collector_brandedtype_nametoGcBoxallocation to support downcasting viaGc::iswithout'staticlifetime boundsGc::getmethod toinner_refto avoid shadowingDereftrait methodsMotivation
These API additions fill the remaining functionality gaps in the branded collector.
Note: This branch (
boa_api) is currently being used as thegitdependency source for the active GC integration effort over atboa-dev/boa(see boa-dev/boa#5460).