diff --git a/changelog.d/7977-lint-red-gcheader-cast.md b/changelog.d/7977-lint-red-gcheader-cast.md new file mode 100644 index 0000000000..28d5d63800 --- /dev/null +++ b/changelog.d/7977-lint-red-gcheader-cast.md @@ -0,0 +1,7 @@ +### Fixed + +- **`lint` was red on `main`**, so every merge was bypassing a required context. `scripts/addr_class_inventory.py` flagged one violation — `crates/perry-runtime/src/object/tests.rs:646` `[gcheader-cast]`, a bare `(obj as *const u8).sub(GC_HEADER_SIZE) as *const GcHeader` added by #7928's inline-slot-floor probe. + + Replaced with the approved accessor `addr_class::try_read_gc_header`, which takes the object address and performs the header arithmetic behind its plausibility and slab checks. The audit passes again (1056 files, 546 ratcheted sites), with no new allowlist entry — the ratchet's whole point is that a fix deletes the violation rather than exempting it. + + Worth stating plainly because it is the shape CLAUDE.md warns about: a **required** context that is red trains everyone to bypass it, and a genuinely new violation would then land invisibly behind the old one. diff --git a/crates/perry-runtime/src/object/tests.rs b/crates/perry-runtime/src/object/tests.rs index 83526520d2..c0115bd5d9 100644 --- a/crates/perry-runtime/src/object/tests.rs +++ b/crates/perry-runtime/src/object/tests.rs @@ -643,8 +643,14 @@ fn two_field_literal_footprint_is_exactly_accounted() { let obj = js_object_alloc_with_shape(0x7916_0001, 2, keys.as_ptr(), keys.len() as u32); assert!(!obj.is_null()); let recorded = unsafe { - let gc = (obj as *const u8).sub(crate::gc::GC_HEADER_SIZE) as *const crate::gc::GcHeader; - (*gc).size as usize + // #7928 added this probe with a bare `as *const GcHeader`, which the + // addr-class ratchet rejects (and which turned required `lint` red on + // `main`). `try_read_gc_header` is the approved accessor: it takes the + // OBJECT address and does the header arithmetic itself, behind the + // plausibility and slab checks. + crate::value::addr_class::try_read_gc_header(obj as usize) + .expect("a freshly allocated object must carry a readable GcHeader") + .size as usize }; let expected = crate::gc::GC_HEADER_SIZE + std::mem::size_of::()