Skip to content

cli: remove unsafe from bun run / bun test / --filter and the other CLI commands - #40242

Open
Jarred-Sumner wants to merge 33 commits into
claude/buntest-zero-unsafefrom
claude/cli-zero-unsafe
Open

Jarred-Sumner wants to merge 33 commits into
claude/buntest-zero-unsafefrom
claude/cli-zero-unsafe

Conversation

@Jarred-Sumner

Copy link
Copy Markdown
Collaborator

What

Same programme as #40055 … #40240. Stacked on #40235 (base branch claude/buntest-zero-unsafe; retarget to main once that lands). Takes src/runtime/cli/ to zero: run_command.rs 79 → 0, test_command.rs 26 → 0, filter_run.rs 27 → 0, multi_run.rs 25 → 0, create_command.rs 33 → 0, pm_trusted_command.rs 26 → 0, bunx_command.rs 12 → 0, repl_command.rs 12 → 0, test/Scanner.rs 10 → 0, open.rs 7 → 0, and the long tail (package_manager_command, install_command, update_interactive_command, exec_command, outdated_command, build_command, filter_arg, scan_command, install_completions_command, pm_update_package_json, init_command, pm_pkg_command, pm_version_command, add_completions, audit_command, dedupe_command, why_command) → 0. Residuals are attribute-only: mod.rs 1 (unsafe extern "C" { safe fn Bun__WebView__hostMain }), Arguments.rs 10 / upgrade_command.rs 1 (#[unsafe(no_mangle)] statics read by C++, #[unsafe(link_section)]). Not in scope: pack_command.rs, publish_command.rs, repl.rs, test/ChangedFilesFilter.rs, test/parallel/*.

Where the unsafe went (each with a one-line SAFETY): bun_event_loop::GlobalMiniEventLoop (Copy handle on the never-freed thread singleton; call-scoped borrows like AnyEventLoop::mini_mut); bun_jsc::VirtualMachine::{enable_hot_module_reloading, run_with_api_lock_mut, tick_immediate_tasks, watcher_add_file_by_path_slow}, on_print_error_zig_exception: Option<Box<dyn Fn(&ZigException)>> (no ctx pointer), JSGlobalObject::{expose_node_module_globals, add_gc, repl_setup_global_require}, ConsoleObject::print_values(&[JSValue]); bun_http::async_http::get_many_sync (condvar fan-in); bun_sys::ctrl_c::{set_flag_once, restore_default}, bun_sys::windows::{get_temp_path_w, get_current_directory_w, query_file_basic_information, copy_file_w, create_directory_ex_w}; bun_resolver::{EntryKindResolver::resolve_kind(&self), Entry::kind safe, Entry.abs_path: Cell + set_abs_path(&self), DirEntry::entries, Resolver::rfs}; bun_options_types::context::{ContextData.log private root with set_log/log_mut/log_ref, init_global} (replaces unsafe set_global); bun_core::set_argv safe (RwLock); bun_sourcemap_jsc::ByteRangeMapping::with_map; bun_install::PackageManager::{load_lockfile_from_bytes, migrate_other_lockfile, activate_scripts_node, root_package_json_path}, LoadResult::{meta, packages_need_update}; impl_buffered_reader_parent! borrow = this and bun_ptr::OwnedThis (same hunks as #40204/#40139).

Behaviour note: BuildCommand::exec now returns after its dependency scan and the --analyze install runs after the bundler returns, so a non-install failure on that path is reported through handle_root_error; multi_run keeps the old truncate-at-NUL semantics via CStr::from_bytes_until_nul.

Testing

Debug+ASAN, run directly: run-shell, run_command, preload, if-present, run-eval, run-process-env, run-cjs, filter-workspace (79), multi-run (121), cpu-prof, as-node, markdown-entrypoint, no-orphans, bunx (34), bun-run (295), bun-run-bunfig, bun-test (98), coverage, parallel (34), path-ignore-patterns, lifecycle-snapshot, test-changed, isolation, retry, rerun-each, randomize, shard, timeout-behavior, concurrent-glob, pass-with-no-tests, bunshell (424), hot (12), watch, init (15), bun-pm/pkg/version/why/scan, lifecycle-scripts (122), bun-create (21), bun-upgrade (8), update_interactive_install, bun-add (70), bake ecosystem, repl (177) — pass; environment-only failures (root cwd permission case, registry/dev-server-dependent cases) identical with system bun. Hand-driven old-vs-new comparisons (pre/post scripts, env expansion, --filter '*' build with one failing package, run ./file.ts, run -, x local bin, missing script, --bun run node shebang, test --only-failures, -e, --print, --workspaces) byte-identical. clippy clean on 16 crates; rust-check-all windows-msvc + apple-darwin pass.

@robobun

robobun commented Aug 23, 2026 •

Copy link
Copy Markdown
Collaborator
Updated 1:33 AM PT - Aug 31st, 2026

❌ @Jarred-Sumner, your commit e0ca0d6 has 1 failures in Build #108743 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 40242

That installs a local version of the PR into your bun-40242 executable, so you can run:

bun-40242 --bun

Comment thread src/event_loop/MiniEventLoop.rs Resolved
Comment thread src/install/dedupe.rs Resolved
Comment thread src/runtime/cli/open.rs Resolved
Comment thread src/resolver/resolver.rs Resolved
Comment thread src/router/lib.rs Resolved
Comment thread src/runtime/cli/pm_pkg_command.rs Resolved
Comment thread src/jsc/VirtualMachine.rs Resolved
Comment thread src/http/AsyncHTTP.rs Resolved
Comment thread src/runtime/cli/repl_command.rs Resolved
Comment thread src/io/PipeReader.rs Resolved

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed the two 22:37 findings are addressed in 03839e4: repl_command.rs now uses run_with_api_lock_mut(|vm| ReplRunner::start(&mut runner, vm)), and the unused reader = arm / BufferedReaderOwner machinery is gone from src/io. The new build_command.rs nit is the same Stacked-Borrows class at one more site.

Extended reasoning...

Commit 03839e4 landed after my previous review round and addresses both open findings from that round. Verified at HEAD: repl_command.rs:147 calls run_with_api_lock_mut with the VM threaded through, and grep for reader =/BufferedReaderOwner/__impl_buffered_reader_owner in src/io returns nothing. The only new item this run is the build_command.rs:590 env_mut()-held-across-generate_from_cli nit posted inline — same Miri-theoretical tag-pop class as the three sites already fixed in this PR. Not approving given the size and scope (72 files across CLI dispatch, filter/multi-run process orchestration, resolver Entry mutability, lockfile load-result reshaping); a human look is warranted regardless.

Comment thread src/runtime/cli/build_command.rs Resolved
Comment thread src/runtime/cli/filter_run.rs Resolved
Comment thread src/runtime/cli/pm_why_command.rs Resolved
Comment thread src/runtime/cli/test_command.rs Resolved
Comment thread src/runtime/cli/multi_run.rs Resolved
Comment thread src/options_types/context.rs Resolved
Comment thread src/runtime/cli/test/Scanner.rs Resolved
Comment thread src/runtime/cli/create_command.rs Resolved

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this pass and found no new issues; the last open note on create_command.rs (progress.maybe_refresh() ordering) is addressed in bd0fa6f. Given the size of the change — 74 files across the CLI dispatch, filter_run/multi_run state-machine rewrites, resolver Entry::kind/abs_path receiver changes, new OwnedThis/GlobalMiniEventLoop abstractions, and the ContextData.log API surface change — a maintainer sign-off would still be worthwhile.

Checked this round: the init_global publish ordering now writes fields before store(Release); Scanner no longer holds a &'static FileSystem across the whole-FileSystem Unique retag; filter_run/multi_run ScriptConfig fields consumed at handle-construction time are dropped from the struct; the --analyze install now runs after BuildCommand::exec returns (behaviour note in the description matches).

Extended reasoning...

Overview

This PR eliminates ~300 unsafe blocks from src/runtime/cli/ (run_command 79→0, test_command 26→0, filter_run 27→0, multi_run 25→0, create_command 33→0, and the long tail), stacked on #40235. The unsafe migrates to a small set of new safe wrappers each carrying a one-line SAFETY: GlobalMiniEventLoop (Copy handle over the thread singleton), OwnedThis<T> (Box-like owner that lends ThisPtr), get_many_sync (condvar fan-in), bun_sys::ctrl_c, VirtualMachine/JSGlobalObject helpers, and resolver Entry::kind/abs_path moving to &self + Cell. ContextData.log becomes private Option<NonNull<Log>> with set_log/log_mut/log_ref/log_ptr, and init_global replaces set_global. filter_run/multi_run are rewritten from raw-pointer backref graphs to Cell/RefCell/OnceCell + index-based dependents. LoadResult grows a Copy LoadMeta so callers can release the &mut Lockfile before saving.

Security risks

None identified. No new external-input parsing, no auth/crypto/TLS changes; the ctrl_c helper replaces two hand-rolled sigaction/SetConsoleCtrlHandler blocks with a shared wrapper. set_argv is now RwLock-guarded rather than an unsynchronized static write.

Level of scrutiny

High. This is a broad memory-model refactor of the CLI process-orchestration paths (--filter, --parallel, bun test, bunx, bun create) plus resolver/event-loop plumbing they sit on. Every prior review round surfaced Stacked-Borrows nits (singleton-getter under a protected &mut, retag-pops-raw-tag), each addressed in a follow-up commit — ~12 fix commits over the review. The PR description's testing section is extensive (debug+ASAN across the affected suites, byte-identical old-vs-new comparisons), and this pass's bug hunt found nothing new. But the surface area — new OwnedThis/ThisPtr ownership model in bun_ptr, the impl_buffered_reader_parent! borrow = this variant, GlobalMiniEventLoop, the ContextData accessor redesign, and the --analyze control-flow change (install now runs after the bundler returns rather than inside on_analyze) — is well past what an automated pass should sign off alone.

Other factors

All 12+ prior inline findings are resolved with named fix commits; the last (create_command maybe_refresh ordering) is fixed in bd0fa6f at HEAD. The PR is stacked on #40235 and will retarget to main. No CODEOWNERS check performed here, but src/runtime/cli/, src/resolver/, src/jsc/VirtualMachine.rs are maintainer-owned areas.

@Jarred-Sumner
Jarred-Sumner force-pushed the claude/buntest-zero-unsafe branch from 3366239 to 2f9324b Compare August 24, 2026 22:50
@Jarred-Sumner
Jarred-Sumner force-pushed the claude/cli-zero-unsafe branch from bd0fa6f to 1b6cb06 Compare August 24, 2026 23:15

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this PR across several passes and the earlier inline findings have all been addressed; this run found no further issues. Given the scope — 74 files reshaping the aliasing model for CLI dispatch, the mini event loop, filter_run/multi_run, the resolver's Entry accessors, and the lockfile load-result plumbing — a human look is still warranted before merge.

What was reviewed:

  • Singleton-getter-under-live-&mut sites (loop_ptr, get_many_sync, repl/build/test_command, install/pm log paths, Scanner readdir, create_command progress node) — the flagged instances were fixed and no new ones surfaced.
  • init_global publish ordering, ScriptConfig dead-field carry in filter_run/multi_run, and the PmWhyCommand dead _ctx param — all addressed.
  • --analyze reshaping in install_command / pm_update_package_json — install now runs after BuildCommand::exec returns, so a non-install failure reports through handle_root_error (noted in the PR description); behavior otherwise preserved.
Extended reasoning...

Overview

This PR removes unsafe from src/runtime/cli/ (run/test/filter/multi_run/create/bunx/repl/pm_* and the long tail) by pushing the unsafe operations behind typed wrappers in lower crates: GlobalMiniEventLoop (Copy handle over the thread singleton), bun_ptr::OwnedThis, ContextData::{set_log,log_mut,log_ref,log_ptr} + init_global, bun_http::get_many_sync, bun_sys::ctrl_c + Windows FFI wrappers, Entry::{kind,abs_path} going Cell-based with EntryKindResolver::resolve_kind(&self), LoadMeta split from LoadResult, and the impl_buffered_reader_parent! borrow = this arm. filter_run/multi_run are rebuilt around OwnedThis<ProcessHandle> + Cell/RefCell state and index-based dependents; --analyze moves the install out of the bundler callback.

Security risks

None identified. The changes are internal aliasing/ownership reshaping of CLI-only paths; no auth, no untrusted-input parsing surface, no crypto/TLS changes. The Windows FFI is wrapped rather than expanded.

Level of scrutiny

High. 74 files, several new cross-crate abstractions (GlobalMiniEventLoop, OwnedThis, LoadMeta, the borrow = this macro arm), a behavior-visible reshaping of --analyze, and a wholesale rebuild of the filter_run/multi_run process-handle graph. This is the class of change REVIEW.md's Architecture & layering and Treat every refactor as guilty until proven behavior-preserving rules exist for. Prior review passes surfaced ~10 Stacked-Borrows-lineage / dead-state findings, all of which the author fixed — but that history itself argues for a maintainer sign-off on the final shape rather than an automated approval.

Other factors

The PR is stacked on #40235 (base branch claude/buntest-zero-unsafe). The author reports extensive debug+ASAN test coverage plus byte-identical old-vs-new comparisons, and every prior review thread on this PR is resolved. No outstanding human review comments.

@Jarred-Sumner
Jarred-Sumner force-pushed the claude/buntest-zero-unsafe branch from 2f9324b to 4a2425a Compare August 24, 2026 23:42
@Jarred-Sumner
Jarred-Sumner force-pushed the claude/cli-zero-unsafe branch from 1b6cb06 to bc8219f Compare August 24, 2026 23:45

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this PR and this pass found no new issues; all earlier rounds' findings (Stacked-Borrows singleton-under-protected-&mut sites, dead ScriptConfig fields, init_global publish ordering, PmWhyCommand dead param, create_command progress-node retag) have been addressed. Given the scope — ~74 files reshaping CLI dispatch, filter_run/multi_run state to Cell/OwnedThis/ThisPtr, ContextData.log ownership, LoadResult→LoadMeta, new GlobalMiniEventLoop/get_many_sync/ctrl_c helpers, and the --analyze control-flow change — a human pass is still warranted.

What was reviewed:

  • Behaviour preservation across the filter_run/multi_run rewrite (dependency graph, pre/main/post chaining, abort/finish accounting, envp/PATH build) and bunx/create/open buffer-lifetime changes.
  • The --analyze reshape in install_command/pm_update_package_json/build_command: install now runs after BuildCommand::exec returns; the early return Ok(()) for the scanner path is guarded by fetcher.is_some().
  • New helpers (OwnedThis, GlobalMiniEventLoop, read_cell, ctrl_c::set_flag_once, get_many_sync, LoadMeta) for correct drop/ownership and no aliasing regressions vs. the code they replace.
Extended reasoning...

Overview

This PR is the CLI tranche of the ongoing unsafe-removal programme (stacked on #40235). It takes src/runtime/cli/ from ~300 unsafe blocks to effectively zero across run_command, test_command, filter_run, multi_run, create_command, bunx_command, repl_command, pm_*, open, Scanner, and the long tail. To do so it introduces or extends several primitives in lower crates: bun_ptr::OwnedThis, bun_event_loop::GlobalMiniEventLoop, bun_io::impl_buffered_reader_parent!{ borrow = this }/BufferedReader::read_cell, bun_http::async_http::get_many_sync, bun_sys::ctrl_c, bun_sys::windows::{query_file_basic_information, copy_file_w, create_directory_ex_w}, bun_install::lockfile::LoadMeta, PackageManager::{load_lockfile_from_bytes, migrate_other_lockfile, activate_scripts_node, root_package_json_path}, and reshapes ContextData.log from a public *mut Log to a private Option<NonNull<Log>> behind log_mut/log_ref/log_ptr/set_log with init_global allocating and publishing the context.

The two largest structural rewrites are filter_run and multi_run: ProcessHandle/State move from raw-pointer backrefs and self-referential Box<[ProcessHandle]> to OwnedThis<ProcessHandle> + BackRef<State> with Cell/RefCell/OnceCell interior mutability, dependents become index vectors, envp is built once per script instead of PATH-swapping the shared loader at spawn time, and the AbortHandler is replaced by bun_sys::ctrl_c. The --analyze path in install_command/pm_update_package_json no longer runs the install inside the bundler's on_analyze callback; instead the callback records positionals and the install runs after BuildCommand::exec returns (which now early-returns after the dependency scan when a fetcher is present).

Security risks

None specific to this PR. It does not add new user-input parsing, network endpoints, or trust boundaries. The ctrl_c handler and Windows FFI wrappers replace existing per-file copies with shared helpers of the same shape. No auth/crypto/TLS logic is touched beyond passing an existing reject_unauthorized flag unchanged.

Level of scrutiny

High. This is a very large refactor (74 files, several thousand lines of net churn) of core CLI dispatch, process spawning/pipe accounting, and package-manager entry points — code that every bun run/bun test/bun install/bun x invocation goes through. The changes are largely mechanical unsafe-removal, but several are genuine control-flow reshapes (--analyze, filter_run/multi_run lifecycle, create_command progress/scopeguard removal, open.rs argv construction, pm_trusted_command load/save split via LoadMeta) whose behaviour-preservation depends on invariants that are easy to get subtly wrong. The PR description reports a broad debug+ASAN test run and byte-identical hand comparisons, and six earlier bug-hunting rounds surfaced ~15 findings that were all fixed in follow-up commits.

Other factors

Every prior review thread on this PR is resolved. The remaining structural risk is the sheer breadth: e.g. the filter_run/multi_run rewrite changes when envp is materialised, how dependents are keyed, and how finish/abort interleave with pipe callbacks; create_command replaces several scopeguard::defer! node-completion paths with straight-line complete_one() calls; command::get() now returns &'static ContextData instead of &'static mut. None of these tripped the bug-hunting system on this pass, but they are the kind of change a maintainer should skim before merge. This is well outside the "simple, mechanical, obvious" bar for auto-approval.

@Jarred-Sumner
Jarred-Sumner force-pushed the claude/buntest-zero-unsafe branch from 4a2425a to d236c14 Compare August 27, 2026 08:25
@Jarred-Sumner
Jarred-Sumner force-pushed the claude/cli-zero-unsafe branch from bc8219f to 5fe2401 Compare August 27, 2026 10:34

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All fifteen inline threads from the earlier passes are addressed in the eaf6b03…5fe24013 push — I re-checked each fix site and the one new rebase commit and found nothing further. Given the size (74 files, ~7k line churn) and that this rewrites aliasing/provenance contracts across OwnedThis, GlobalMiniEventLoop, ContextData::log, ProcessHandle, and the resolver/fs &self-mutation surface, a human pass is still worthwhile before merge.

What was reviewed on this push:

  • get_many_sync now owns requests as OwnedThis and derives the callback ctx from this_ptr(); on_print_error_zig_exception is written explicitly in VirtualMachine::init.
  • init_global publishes GLOBAL_CLI_CTX after set_log/start_time; filter_run builds argv[2] via from_bytes_until_nul to match multi_run; create_command refreshes progress before lending progress.root.
  • repl_command threads &mut VirtualMachine through run_with_api_lock_mut; the unused reader = arm of impl_buffered_reader_parent! and its supporting types were dropped; to_executable/exe_path now take &Loader so build_command holds a shared borrow across generate_from_cli.
  • Dead _ctx params removed from pm_pkg/pm_version/pm_why; the stale SAFETY/RacyCell/&mut-borrow comments in dedupe/prune/update_transitive/resolver/router/interpreter/open/scan_command/upgrade_command are gone; Scanner holds leaf copies instead of &'static FileSystem; spawn::ProcessHandle accessors read through RefPtr::Deref after the #40478 rebase.
Extended reasoning...

Overview

This branch removes unsafe from the CLI command layer (src/runtime/cli/*), the test runner, and their supporting infrastructure — 74 files, ~3000 insertions / ~4100 deletions. It introduces bun_ptr::OwnedThis<T>, converts RacyCell statics to locked equivalents, replaces raw fn+ctx callback pairs with boxed closures, adds safe wrapper methods on AsyncHTTP/ProcessHandle/ConsoleObject/JSGlobalObject/bun_sys, and reworks aliasing contracts in ContextData, MiniEventLoop, the resolver Entry/DirEntry surface, and filter_run/multi_run process handles. Fifteen inline findings from earlier passes (a mix of Stacked-Borrows provenance regressions, stale SAFETY comments, dead parameters, an alloc_zeroed niche-validity gap, and a debug-panic on user input) were each addressed by a dedicated commit in the eaf6b03…5fe24013 push.

Security risks

No new attack surface: this is an internal safety refactor with no protocol, auth, or input-validation changes. The one user-input-reachable behavioral concern raised earlier (debug-build debug_assert! panic on interior-NUL script values in filter_run) is fixed via from_bytes_until_nul. The get_many_sync helper is used only by first-party CLI paths (upgrade/completions) against Bun-controlled endpoints.

Level of scrutiny

High. This PR rewrites the aliasing and provenance contracts that gate most of the CLI's interaction with process-global singletons (VirtualMachine, FileSystem, ContextData, MiniEventLoop), introduces a new smart-pointer type whose Drop semantics matter, and adds &self-mutating accessors (Entry::set_abs_path via Cell) whose correctness depends on every caller respecting the new interior-mutability shape. The earlier passes surfaced a dozen subtle SB-provenance regressions that were each real under Miri; the fix commits look correct on re-read, but the class of bug is easy to reintroduce and hard to test for outside Miri.

Other factors

No new tests are added (the PR claims byte-identical behavior verified by hand and the existing suite under debug+ASAN). The rebase commit 5fe2401 is a mechanical RefPtr::data() → Deref swap on top of #40478 and reads correctly. All fifteen fix commits do what their subject lines say; the dead reader = macro arm and its ~70 lines of supporting types were removed rather than left speculative. Given the scope and that this is stacked on another open branch, human sign-off remains appropriate.

…uplex.rs

Squash of the branch (previously 15 commits) for the rebase over #40516:

- socket: hold ext-slot/owner refs in typed RefPtr slots instead of bare ref/deref
- socket: hand the closed connection's io_ref to the teardown guard before running close/connectError handlers
- socket: connect-error teardown owns the failed connection's io_ref on the synchronous path too; named-pipe owner takes its ref out before dispatching close/connectError
- review: typed SSL ex-data slot, ContextFunction handle clears its slot on drop, ext slot is one owner pointer, HTTPContext owns its SSL_CTX
- socket: take the closing socket's io_ref before dispatching the upgradeTLS twin's close handler
- host_fn: ContextFunction::new takes a BackRef to the context
- cron: scoped with_cron_jobs callback instead of a &'static mut accessor
- BackRef<_, Root> for the h2 native-socket and duplex owner back-references
- typed ref slots release on drop; ContextFunction takes EncodedSlice
@Jarred-Sumner
Jarred-Sumner force-pushed the claude/buntest-zero-unsafe branch from 3f90307 to 3af4294 Compare August 29, 2026 08:29
TimeoutObject/ImmediateObject/WTFTimer/DateHeaderTimer/EventLoopDelayMonitor
and timer::All no longer contain any unsafe code. The intrusive timer heap is
reached through TimerRef (a handle to a TimerOwner's EventLoopTimer slot) and
TimerHeap in bun_event_loop, which own the links and heap membership;
bun_io::heap::Intrusive keeps its nodes behind Cell links and never forms a
&mut. timer::All is &self-only with interior mutability, so timer callbacks
that re-enter it no longer alias a &mut. The heap's ref on a scheduled JS
timer is a typed RefPtr slot instead of bare ref/deref counting, and the
tag->owner recovery for firing/cancelling timers lives in dispatch.rs.
…o-op for unlinked slots

- drain_due_wtf_timers fires the WTFTimer directly (dispatch::fire_wtf_timer)
  instead of going through the tag dispatch, so nothing reads a WTF slot
  outside the wtf_timers lock; the tag asserts in wtf_arm/wtf_disarm move
  under the lock.
- All::remove is the single 'disarm if armed' entry point: an unlinked slot
  is left alone (and marked CANCELLED) rather than debug-asserting, and the
  DevServerMemoryVisualizerTick arm marks its slot FIRED like every other
  owner, so DevServer's state == ACTIVE guards stay consistent with the heap.
- get_timeout no longer needs the VM.
- drop the unused JsCell::from_mut.
@Jarred-Sumner
Jarred-Sumner force-pushed the claude/cli-zero-unsafe branch from 80c80b6 to e0ca0d6 Compare August 31, 2026 08:11

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review found no issues

No high-confidence issues detected in this change.

@robobun

robobun commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator

A note on the red Linux aarch64 lanes of this branch, in case it helps.

filesystem_router.test.ts (reload() while Bun.build() resolves the same directory) fails in 14 of the 16 finished builds of this branch, for example build 108743 at e0ca0d6: panic: Segmentation fault at address 0x32.

Cause: Entry::set_abs_path(&self) here is self.abs_path.set(p) with no lock. The six resolver sites and Scanner::next call it, and bundler threads and the JS thread fill the same entry. A reader can see the new length with the empty pointer (0x1). Main has the same write as an unlocked &mut *entry store, and it crashed main builds 104102 and 104382 the same way.

#40258 fixes the race: Entry::abs_path_or_try_fill is the only writer of the path, and it fills it once under the per-entry mutex. If #40258 lands first, the rebase here is:

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants