Repository navigation
feat(ts)!: abort where Rust leaves behavior undefined, locate zip's and tokio's panics, and refuse erasing a pointer not shown an Arc's - #661
Conversation
Quest-Claim: a624b21b70dbf7b2
…or undefined, and locate zip's and tokio's panics A read or write through a pointer to no memory, a write through str::as_ptr, Arc::from_raw of a pointer no into_raw gave or of a dropped value, and dealloc or realloc of memory alloc didn't give now abort with std's "unsafe precondition(s) violated" wording rather than a rust2-ts error. A hook program now locates std's Zip::next_back unreachable!() and tokio's oneshot "called after complete", checked against native. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…with the decision they wait on Also keep a mutable slice through str::as_ptr a rust2-ts error, as Stacked Borrows alone makes it undefined, and document the aborts and tokio's sites. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A hook program whose tokio lacks the sync feature compiles no oneshot.rs, whose panic nothing can reach, so its site is left out rather than refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…x remap leaves it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rase of a pointer the body doesn't show is an Arc's Tokio's `Receiver::poll` panic site now comes from the `panic!` call in tokio's own MIR at the mapped call, so rustc names the file as native does under any --remap-path-prefix; the source-file text search is gone. The fixtures remap tokio's src/sync to cover it. A pointer to a value JS copies cast to `*const ()` is refused unless the body shows an Arc's or Rc's into_raw or as_ptr gave it, or that it is null or dangling. AGENTS.md allows a loud run-time check for an unsafe pointer from elsewhere, under m3's unsafe policy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Design change: the maintainer settled the round-3 checkpoint on 2026-11-07.
The review count restarts with (Written by Claude Opus 5.5 with high effort) |
…ping tokio's sync Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 58 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head 8280fdd5cc94a1d753bd56ae1962774c5b4939cd against base 8254acb90050f21f442be92f93e2caaaf3685dff.
No actionable defects found in the inspected changes and surrounding code. I checked the UB-abort paths, pointer-erasure provenance and refusal logic, zip and Tokio panic-site lowering, and the corresponding runtime assertions, rejection fixtures, cast-chain cases, and remapped hook snapshots. The deferred allocation-byte behavior remains explicitly tracked rather than treated as fixed.
Direction: the implementation is consistent with the documented scope. Preserve the differential coverage for null/dangling and Arc cast chains, zip's panic location, and repeated oneshot polling when changing these paths.
Validation limits: GitHub-only static review. I did not run builds, tests, type-checking, or CI. This is a COMMENT review, not an approval or merge recommendation.
(Written by review (OpenAI))
…hrows Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Implements part of quest/m3/ts-runtime-throws.md and rewrites it to what remains.
Problem
The runtime threw a
rust2-ts:error in places where native Rust would keep running. The quest asks to sort every such throw: guards against Rust UB stay, worded as std's precondition aborts; real gaps either translate exactly or get refused at translation.Approach
Each
git grep 'rust2-ts: ' ts/runtimesite, sorted:rs.violated(check)throwsrs.Abortwith std'sunsafe precondition(s) violated: ...text and runs no hook. It now covers:nowhere, plusNO_MEMORY, the empty array null and dangling now point into);str::as_ptr;Arc/Rc::from_rawof a pointer nointo_rawgave, or of a dropped value;dealloc/reallocof memoryallocdidn't give;TrustedLenzip that runs out early. This is std'sunwrap_uncheckedcheck, worded as std words it.Zip::next_backunreachable!()(anExactSizeIteratorwhoselenlies) is now located at thezip_impl_general_defaults!call, the way native places a macro's panic.called after complete: at a mapped<Receiver<T> as Future>::pollin a hook program, translation takes the span of the onepanic!call in tokio's own MIR for thatpolland passes itsrs.Locationtors.oneshotPoll. rustc names the file as native does under any--remap-path-prefix, and a build without tokio'ssyncreaches no such call, so the source-file text search is gone.langfixtures. The only hit wasset_hookinside a hook, which an unpatched runtime aborts before it needs a location. The survey patch was local and is not committed.rs.arcEraseis now refused at translation: a pointer to a value JS copies cast to*const ()translates only where the body shows anArc's orRc'sinto_raworas_ptrgave it, or that it is null or dangling. Its run-time check now guards the translator.ptrUnerase,offset_fromacross arrays,AtIndex.reach, raw slices of a field's byte, andBytes::slice_refof copied bytes stay loud run-time checks. AGENTS.md's "never a runtime failure" rule now allows one for anunsafepointer from elsewhere, citing m3's unsafe policy.alloc's bytes (read, written, or cast to another type through a byte pointer from elsewhere) stay the quest's remaining work. Refusing them needs a use analysis of the byte pointerallocreturns, to show it never leaves the body untyped, which the translator doesn't have yet. That is more than a modest change, so it is left out of this PR.Stepand a fmtCountwritten as a placeholder: no translation produces either;rs.u64Ofand its kin given a number past 2^53: a JS caller's input;str::as_ptrstays with it, since only Stacked Borrows makes it UB.ptr::eqof an arrayas_chunkssplit: an exact path exists (a copy that remembers its slice and offset). It stays in the quest, now building on thers.ArraySlicethat #662 landed.*const [T]comparisons of values JS copies: no exact path exists while a&stris a JS string (#574), so the refusal stays.Tests
ts/tests/pointers.tsnow tells the UB aborts apart from the remainingrust2-ts:failures, including a null pointer moved byadd.lang/panicswith thehookfeature:hooked::sitedkind 86 zips a length-lying iterator from the back.hooked::tokio_stockpolls a oneshot receiver after it completes.caller.tsnow names everysitedkind as an input, since 151 random inputs could miss one.src/syncdirectory totokio/channels, round 3's case, which a text search by path keeps missing. The hook snapshot namestokio/channels/oneshot.rs:1291:13, and the differential matches native. tokio withoutsyncneeds no test of its own: no mappedpollexists there, so nothing is looked up.reject:pointers::erased_unshowncasts a parameter's pointer to*const ().lang/pointersdrops itserase_flagcase, which tested the old run-time path, and adds null pointers erased and compared, made inline, as a constant, and throughcasts to and fromMaybeUninit, and anArc's pointer erased through such a cast.Impact
rs.Abortwith std's precondition text, where they used to throw anErrorstartingrust2-ts:.rs.violated,rs.nowhere,rs.NO_MEMORY.rs.oneshotPolltakes an optionalat?: Location, its panic's location.zip_next_back. Itsrs.oneshotPollcalls pass tokio's location. A program without a hook is unchanged.*const ()is refused unless the body shows anArc's orRc's raw pointer, null, or dangling. Migrate by casting theArc::into_raw/as_ptrresult where it is made.Alternatives
panic_nounwinddoes: rejected, since Rust defines nothing there and these sites have no location.Uint8Array(1)for eachu8field whose address is taken: rejected for now, since any&mut u8a callee turns raw would need one.Decisions
✅ Locating tokio's oneshot panic (maintainer, 2026-11-07, at the round-3 design checkpoint): take the
panic!call's position from tokio's own compiled code forReceiver::pollat the mapped call, so rustc names the file as native does under any--remap-path-prefix. Delete the source-file text search, and test a remapped build.✅ The pointers only run time sees (maintainer, 2026-11-07): refuse at translation, with a span,
arcEraseand reads ofalloc's bytes as values. Keep loud run-time checks forptrUnerase,offset_fromacross arrays,AtIndex.reach, raw slices of a field's byte, andBytes::slice_refof copied bytes. Amend AGENTS.md to allow a loud run-time check for an unsafe pointer from elsewhere whose origin translation can't see, citing m3's unsafe policy. Implement the two refusals here if modest:arcEraseis done;alloc's bytes is left in the quest (see Approach).✅
bytes' panics (maintainer, 2026-11-07): locate them frombytes' compiled code, as tokio's now are, since a remap insidebytesfails translation of a hook program. This goes into the quest's remaining work, not a new quest.Choices made without asking
str::as_ptrstays arust2-ts:error rather than an abort, to match feat(ts): translate str::as_ptr as a read-only pointer into its UTF-8 #634's call on Stacked-Borrows-only UB.Count, tokio's semaphore) are classified rather than changed.bytes' sites keep main's source search. Moving them to compiled code is now the quest's remaining work (see Decisions).*const ()still translates, since the runtime's answer for it is exact.Rcjoins the census's verbatim words, asArcis, for the new refusal's message.Follow-ups
None. The
bytesfollow-up is now in the quest's remaining work.Models
Size: L
Implementer: Claude Code, claude-opus-5-5, high effort
Review
Rewritten by
quest reviewafter each round.01a1b8b4-1012-7200-b461-124a52955a9c, round 4No defects found in the specified branch diff; focused pointer and panic differentials, runtime tests, and TypeScript checks pass.Head d466e2a merges main (#662, #665). Conflicts:
ts/runtime/rs/task.ts's import list, which now takes both sides, and the quest file, which keeps this PR's plan and drops the deleted rs.Slice quest's links. It also addsbytes' panics to the quest's remaining work.quest check --fixandjust cipass, with no snapshot changes.(Written by Claude Opus 5.5 with high effort)