diff --git a/CLAUDE.md b/CLAUDE.md index 9ca2f2b4bb..80f8eb98fd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,7 +8,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co Perry is a native TypeScript compiler written in Rust that compiles TypeScript source code directly to native executables. It uses SWC for TypeScript parsing and LLVM for code generation. -**Current Version:** 0.5.1328 +**Current Version:** 0.5.1329 ## TypeScript Parity Status diff --git a/Cargo.lock b/Cargo.lock index f93ee20ec9..70de9999f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5547,7 +5547,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perry" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", "base64", @@ -5607,14 +5607,14 @@ dependencies = [ [[package]] name = "perry-api-manifest" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "serde", ] [[package]] name = "perry-audio-miniaudio" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "cc", "libc", @@ -5622,7 +5622,7 @@ dependencies = [ [[package]] name = "perry-codegen" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", "inkwell", @@ -5639,7 +5639,7 @@ dependencies = [ [[package]] name = "perry-codegen-arkts" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", "perry-hir", @@ -5647,7 +5647,7 @@ dependencies = [ [[package]] name = "perry-codegen-glance" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", "perry-hir", @@ -5655,7 +5655,7 @@ dependencies = [ [[package]] name = "perry-codegen-js" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", "perry-dispatch", @@ -5664,7 +5664,7 @@ dependencies = [ [[package]] name = "perry-codegen-swiftui" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", "perry-hir", @@ -5672,7 +5672,7 @@ dependencies = [ [[package]] name = "perry-codegen-wasm" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", "base64", @@ -5684,7 +5684,7 @@ dependencies = [ [[package]] name = "perry-codegen-wear-tiles" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", "perry-hir", @@ -5692,7 +5692,7 @@ dependencies = [ [[package]] name = "perry-container-compose" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", "async-trait", @@ -5721,14 +5721,14 @@ dependencies = [ [[package]] name = "perry-container-e2e" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", ] [[package]] name = "perry-diagnostics" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "serde", "serde_json", @@ -5736,7 +5736,7 @@ dependencies = [ [[package]] name = "perry-dispatch" -version = "0.5.1328" +version = "0.5.1329" [[package]] name = "perry-doc-fixture-my-bindings" @@ -5747,7 +5747,7 @@ dependencies = [ [[package]] name = "perry-doc-tests" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", "clap", @@ -5762,7 +5762,7 @@ dependencies = [ [[package]] name = "perry-ext-ads" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "block2", "objc2", @@ -5772,7 +5772,7 @@ dependencies = [ [[package]] name = "perry-ext-argon2" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "argon2", "perry-ffi", @@ -5780,7 +5780,7 @@ dependencies = [ [[package]] name = "perry-ext-axios" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ffi", "reqwest", @@ -5789,7 +5789,7 @@ dependencies = [ [[package]] name = "perry-ext-bcrypt" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "bcrypt", "perry-ffi", @@ -5797,7 +5797,7 @@ dependencies = [ [[package]] name = "perry-ext-better-sqlite3" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ffi", "rusqlite", @@ -5805,7 +5805,7 @@ dependencies = [ [[package]] name = "perry-ext-cheerio" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ffi", "scraper", @@ -5813,7 +5813,7 @@ dependencies = [ [[package]] name = "perry-ext-commander" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ffi", "perry-runtime", @@ -5821,7 +5821,7 @@ dependencies = [ [[package]] name = "perry-ext-cron" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "chrono", "cron", @@ -5831,7 +5831,7 @@ dependencies = [ [[package]] name = "perry-ext-dayjs" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "chrono", "perry-ffi", @@ -5839,7 +5839,7 @@ dependencies = [ [[package]] name = "perry-ext-decimal" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ffi", "rust_decimal", @@ -5847,7 +5847,7 @@ dependencies = [ [[package]] name = "perry-ext-dotenv" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ffi", "serde_json", @@ -5855,7 +5855,7 @@ dependencies = [ [[package]] name = "perry-ext-ethers" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ffi", "rand 0.10.1", @@ -5863,7 +5863,7 @@ dependencies = [ [[package]] name = "perry-ext-events" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ffi", "perry-runtime", @@ -5871,14 +5871,14 @@ dependencies = [ [[package]] name = "perry-ext-exponential-backoff" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ffi", ] [[package]] name = "perry-ext-fastify" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "bytes", "http-body-util", @@ -5896,7 +5896,7 @@ dependencies = [ [[package]] name = "perry-ext-fetch" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "bytes", "lazy_static", @@ -5909,7 +5909,7 @@ dependencies = [ [[package]] name = "perry-ext-http" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "bytes", "h2", @@ -5933,7 +5933,7 @@ dependencies = [ [[package]] name = "perry-ext-ioredis" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "lazy_static", "perry-ffi", @@ -5943,7 +5943,7 @@ dependencies = [ [[package]] name = "perry-ext-jsonwebtoken" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "base64", "jsonwebtoken", @@ -5954,7 +5954,7 @@ dependencies = [ [[package]] name = "perry-ext-lru-cache" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "lru", "perry-ffi", @@ -5963,7 +5963,7 @@ dependencies = [ [[package]] name = "perry-ext-moment" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "chrono", "perry-ffi", @@ -5971,7 +5971,7 @@ dependencies = [ [[package]] name = "perry-ext-mongodb" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "bson", "futures-util", @@ -5983,7 +5983,7 @@ dependencies = [ [[package]] name = "perry-ext-mysql2" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "chrono", "perry-ffi", @@ -5993,7 +5993,7 @@ dependencies = [ [[package]] name = "perry-ext-nanoid" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "nanoid", "perry-ffi", @@ -6002,7 +6002,7 @@ dependencies = [ [[package]] name = "perry-ext-net" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "bytes", "perry-ffi", @@ -6015,7 +6015,7 @@ dependencies = [ [[package]] name = "perry-ext-node-forge" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "const-oid 0.9.6", "der 0.7.10", @@ -6034,7 +6034,7 @@ dependencies = [ [[package]] name = "perry-ext-nodemailer" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "lettre", "perry-ffi", @@ -6044,7 +6044,7 @@ dependencies = [ [[package]] name = "perry-ext-pdf" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ffi", "printpdf", @@ -6052,7 +6052,7 @@ dependencies = [ [[package]] name = "perry-ext-pg" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ffi", "sqlx", @@ -6061,7 +6061,7 @@ dependencies = [ [[package]] name = "perry-ext-ratelimit" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "governor", "perry-ffi", @@ -6069,7 +6069,7 @@ dependencies = [ [[package]] name = "perry-ext-sharp" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "fast_image_resize", "image", @@ -6079,14 +6079,14 @@ dependencies = [ [[package]] name = "perry-ext-slugify" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ffi", ] [[package]] name = "perry-ext-streams" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "lazy_static", "perry-ffi", @@ -6095,7 +6095,7 @@ dependencies = [ [[package]] name = "perry-ext-undici" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ffi", "perry-runtime", @@ -6104,7 +6104,7 @@ dependencies = [ [[package]] name = "perry-ext-uuid" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ffi", "uuid", @@ -6112,7 +6112,7 @@ dependencies = [ [[package]] name = "perry-ext-validator" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ffi", "regex", @@ -6122,7 +6122,7 @@ dependencies = [ [[package]] name = "perry-ext-ws" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "futures-util", "lazy_static", @@ -6135,7 +6135,7 @@ dependencies = [ [[package]] name = "perry-ext-zlib" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "brotli", "flate2", @@ -6145,7 +6145,7 @@ dependencies = [ [[package]] name = "perry-ffi" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "dashmap", "once_cell", @@ -6154,7 +6154,7 @@ dependencies = [ [[package]] name = "perry-hir" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", "perry-api-manifest", @@ -6172,7 +6172,7 @@ dependencies = [ [[package]] name = "perry-parser" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", "perry-diagnostics", @@ -6184,7 +6184,7 @@ dependencies = [ [[package]] name = "perry-runtime" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", "base64", @@ -6226,14 +6226,14 @@ dependencies = [ [[package]] name = "perry-runtime-static" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-runtime", ] [[package]] name = "perry-stdlib" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "aes 0.8.4", "aes 0.9.1", @@ -6328,14 +6328,14 @@ dependencies = [ [[package]] name = "perry-stdlib-static" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-stdlib", ] [[package]] name = "perry-transform" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", "perry-hir", @@ -6344,14 +6344,14 @@ dependencies = [ [[package]] name = "perry-ui" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ui-model", ] [[package]] name = "perry-ui-android" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "base64", "itoa", @@ -6368,7 +6368,7 @@ dependencies = [ [[package]] name = "perry-ui-geisterhand" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "rand 0.10.1", "serde", @@ -6378,7 +6378,7 @@ dependencies = [ [[package]] name = "perry-ui-gtk4" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "base64", "cairo-rs 0.22.0", @@ -6401,7 +6401,7 @@ dependencies = [ [[package]] name = "perry-ui-ios" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "base64", "block2", @@ -6417,7 +6417,7 @@ dependencies = [ [[package]] name = "perry-ui-macos" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "base64", "block2", @@ -6432,7 +6432,7 @@ dependencies = [ [[package]] name = "perry-ui-model" -version = "0.5.1328" +version = "0.5.1329" [[package]] name = "perry-ui-test" @@ -6443,11 +6443,11 @@ dependencies = [ [[package]] name = "perry-ui-testkit" -version = "0.5.1328" +version = "0.5.1329" [[package]] name = "perry-ui-tvos" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "base64", "block2", @@ -6463,7 +6463,7 @@ dependencies = [ [[package]] name = "perry-ui-visionos" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "base64", "block2", @@ -6479,7 +6479,7 @@ dependencies = [ [[package]] name = "perry-ui-watchos" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "block2", "libc", @@ -6492,7 +6492,7 @@ dependencies = [ [[package]] name = "perry-ui-windows" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "base64", "libc", @@ -6509,14 +6509,14 @@ dependencies = [ [[package]] name = "perry-ui-windows-winui" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "perry-ui-windows", ] [[package]] name = "perry-updater" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "anyhow", "base64", @@ -6532,7 +6532,7 @@ dependencies = [ [[package]] name = "perry-wasm-host" -version = "0.5.1328" +version = "0.5.1329" dependencies = [ "wasmi", ] diff --git a/Cargo.toml b/Cargo.toml index 1913529c47..8c0ee4a942 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -315,7 +315,7 @@ codegen-units = 16 codegen-units = 16 [workspace.package] -version = "0.5.1328" +version = "0.5.1329" edition = "2021" license = "MIT" repository = "https://github.com/PerryTS/perry" diff --git a/changelog.d/7585-addr-class-mark-shape-shared.md b/changelog.d/7585-addr-class-mark-shape-shared.md new file mode 100644 index 0000000000..61477f029c --- /dev/null +++ b/changelog.d/7585-addr-class-mark-shape-shared.md @@ -0,0 +1,42 @@ +### Fixed + +- **`lint` was red on `main` and on every open PR (#7585).** #7579 added a bare + `as *mut GcHeader` cast in `iter_result.rs` to stamp the shared iterator-result + keys array copy-on-write, and `scripts/addr_class_inventory.py` refuses that + outside `gc/` and `value/addr_class.rs`. It was found by an agent working an + unrelated issue that happened to touch the same file — not by the gate + blocking a merge, because merges were bypassing it. + + **Not fixed with a 127th allowlist entry, deliberately.** Every one of the 126 + grandfathered entries in `scripts/addr_class_allowlist.txt` carries the same + sentence — *"migrate to `addr_class::try_read_gc_header` in a follow-up"* — so + adding another borrows against a debt nobody is paying down. + + The reason none of them has migrated is **structural rather than neglect**, and + it is worth writing down because it will otherwise be rediscovered: + `try_read_gc_header` returns `&'static GcHeader`, a **shared** reference. That + is the whole point of it — it is the safe probe for an address that might be in + the handle band, so it must not be able to write through what it validates. But + these call sites do not want to read a header; they want to **set a flag**. No + amount of follow-up work makes a shared reference serve a `*mut` write. The + migration target the allowlist kept promising did not exist. + + So this adds it. `gc::mark_shape_shared` lives in `gc/`, where the cast is + permitted, and states the precondition the allowlist entries were implicitly + relying on: the pointer must be the user pointer of an object this thread has + just allocated, never an address decoded from a NaN-box payload — the same + discipline the arena walkers are already allowlisted under, and the reason no + handle band can reach it. `iter_result.rs` calls it and the cast is gone. The + allowlist does not grow, and the remaining sites now have a real target. + + Also drops one stale addr-class ratchet entry that the tool itself reported as + over-counted (`object/field_get_set.rs` `lone-valid-obj-ptr`: baseline says 1, + found 0). Same family as #7582 — a suppression that outlived its subject, and + a ratchet is only as tight as its least-current entry. + + Validation: `addr_class_inventory.py` passes (885 files scanned, 267 + allowlisted, 542 sites held by the ratchet); `cargo test -p perry-runtime + --lib` 1818 passed / 0 failed, including + `shared_iter_result_keys_are_marked_copy_on_write`, which is the test guarding + this exact flag write; `raw_handle_debt` 998 (baseline 998); + `check_file_size.sh` and `cargo fmt --check` clean. diff --git a/crates/perry-runtime/src/gc/mod.rs b/crates/perry-runtime/src/gc/mod.rs index e9b34353cf..546f231b73 100644 --- a/crates/perry-runtime/src/gc/mod.rs +++ b/crates/perry-runtime/src/gc/mod.rs @@ -912,6 +912,33 @@ pub extern "C" fn js_gc_pause_stats( }); } +/// Stamp a freshly built, runtime-owned keys array as copy-on-write shared. +/// +/// The `*mut GcHeader` cast lives HERE, in `gc/`, rather than at the call site. +/// `scripts/addr_class_inventory.py` refuses a bare `as *mut GcHeader` outside +/// `gc/` and `value/addr_class.rs`, and every one of the ~126 grandfathered +/// entries in `scripts/addr_class_allowlist.txt` carries the same promise — +/// "migrate to a helper in a follow-up". This is that helper for the one thing +/// those call sites actually do: set a flag. +/// +/// `addr_class::try_read_gc_header` cannot serve them, and that is not an +/// oversight — it returns `&'static GcHeader`, a SHARED reference, precisely so +/// that a probe of an untrusted address can never write through it. A flag +/// write needs `*mut`, so it needs a separate, narrower entry point with a +/// stronger precondition, which is what this is. +/// +/// # Safety +/// `user_ptr` must be the user pointer of a live GC object this thread has just +/// allocated — never an address decoded from a NaN-box payload. That is the +/// same discipline the arena walkers are allowlisted under: an address obtained +/// from allocation or block iteration cannot be in the handle band, so there is +/// nothing for `try_read_gc_header`'s band check to reject. +#[inline] +pub(crate) unsafe fn mark_shape_shared(user_ptr: *mut u8) { + let header = layout::header_from_user_ptr(user_ptr); + (*header).gc_flags |= GC_FLAG_SHAPE_SHARED; +} + #[cfg(test)] mod tests; diff --git a/crates/perry-runtime/src/iter_result.rs b/crates/perry-runtime/src/iter_result.rs index c87a930e42..832e567d81 100644 --- a/crates/perry-runtime/src/iter_result.rs +++ b/crates/perry-runtime/src/iter_result.rs @@ -136,8 +136,7 @@ unsafe fn build_shared_keys(order: IterResultOrder) { // Copy-on-write marker. Without it, `result.extra = 1` on ONE result // object would append to the array every other result shares. - let gc_header = (keys as *mut u8).sub(crate::gc::GC_HEADER_SIZE) as *mut crate::gc::GcHeader; - (*gc_header).gc_flags |= crate::gc::GC_FLAG_SHAPE_SHARED; + crate::gc::mark_shape_shared(keys as *mut u8); ITER_RESULT_KEYS.with(|c| (*c.get())[order as usize] = keys); crate::gc::runtime_write_barrier_root_raw_ptr(keys); diff --git a/scripts/addr_class_ratchet_baseline.txt b/scripts/addr_class_ratchet_baseline.txt index 7d2dcf3009..5db87b7712 100644 --- a/scripts/addr_class_ratchet_baseline.txt +++ b/scripts/addr_class_ratchet_baseline.txt @@ -234,7 +234,6 @@ lone-valid-obj-ptr | crates/perry-runtime/src/object/class_registry/class_meta.r lone-valid-obj-ptr | crates/perry-runtime/src/object/class_registry/construct.rs | 6 lone-valid-obj-ptr | crates/perry-runtime/src/object/class_registry/prototype_objects.rs | 1 lone-valid-obj-ptr | crates/perry-runtime/src/object/descriptors.rs | 2 -lone-valid-obj-ptr | crates/perry-runtime/src/object/field_get_set.rs | 1 lone-valid-obj-ptr | crates/perry-runtime/src/object/field_get_set/accessors.rs | 2 lone-valid-obj-ptr | crates/perry-runtime/src/object/field_get_set/enumeration.rs | 3 lone-valid-obj-ptr | crates/perry-runtime/src/object/field_get_set/field_ops.rs | 1