Skip to content

fix(resolver): synchronize mutable entry-cache snapshots - #89

Merged
steipete merged 2 commits into
mainfrom
claude/w111-worker-resolve-race
Oct 3, 2026
Merged

steipete merged 2 commits into
mainfrom
claude/w111-worker-resolve-race

Conversation

@steipete

@steipete steipete commented Oct 3, 2026 •

Copy link
Copy Markdown

Concurrent worker resolution can read a torn symlink path from the process-global filesystem entry cache. need_stat publishes a lazy fill, but it does not protect readers from later symlink fills, fd updates, or re-stats. A ThreadSanitizer test against the real Entry methods reports the unlocked Cell<EntryCache>::get racing set_cache_symlink (exit 66).

Use Bun's existing Guarded<EntryCache> for complete snapshots and field updates. The outer entry mutex still coordinates stat/fd lifecycle operations; lock order is outer entry mutex then cache mutex. Remove the manual Entry Send/Sync declarations. Two concurrent cache tests join the existing Miri runner; unrelated native-SIMD data-URL tests remain enabled outside Miri.

Validation so far:

  • Unpatched TSan cache diagnostic fails with a data race; patched symlink-fill and re-stat tests pass TSan and Miri.
  • Patched ASAN stress: 210 seconds, 256 worker lifetimes, 262,144 imports/requires/resolutions, and 3,615 concurrent symlink-churn/router-reload/build iterations; no sanitizer report.
  • Original OpenClaw v6 tooling pair at its exact revision, maxWorkers=32: patched 10/10, 230 assertions; Node control passes.
  • Same-toolchain release builds, 8 samples each in ABBA order: warm symlink resolution +1.6%, plain paths +3.6% (about 19ns/resolve), eight-worker contention +5.4%.
  • Independent P2 review: scoped-clean. All 12 Rust target triples passed; all-target resolver clippy and formatting passed.
  • ASAN surrounding resolver/router/worker and source-lint suites: 557 pass, 2 skip, one independently confirmed baseline failure (import override to bun:test); no sanitizer report.

Scope and upstream: oven-sh#37274 explicitly left mutable-cache readers for follow-up. Open oven-sh#40258 fixes the separate abs_path publication race, not this cache. The original consumer SIGSEGV has not recurred; the TSan cache race is the reproduced defect. A more aggressive native stress fixture also produces a JS module-not-found error with a directory-only resolved path on both baseline and patched binaries; this separate remaining resolution failure is not claimed fixed. The existing numeric-fd lifetime/close protocol is unchanged.

Both fork native CI lanes passed on final head b3412cd06ddc85b888e25b7c56d1f9bf94e0ff48: Linux x64 and Darwin arm64. Final-head Rust/Miri, format, JS lint, and source checks also passed. The resolver suite's import override to bun:test failure also reproduces on unpatched e167 and is unrelated to cache synchronization.

Protect symlink slices and stat/fd cache snapshots with Guarded while preserving the existing entry lifecycle mutex. Add concurrent fill and re-stat regression coverage to Miri; the unpatched cache fails ThreadSanitizer.
Use explicit raw pointers and recognized safety comments in the concurrent cache tests. Clarify that the compatibility note covers cache snapshots.
@steipete
steipete merged commit d894d7f into main Oct 3, 2026
11 checks passed
@steipete
steipete deleted the claude/w111-worker-resolve-race branch October 3, 2026 10:07
steipete added a commit that referenced this pull request Oct 5, 2026
Bound the macOS runtime transpiler cache to one write transaction at a time. Parallel file creation and rename contend inside APFS, spending kernel CPU across Bun Pool workers. Parsing, resolution, cache reads, cache bytes and atomic publication remain unchanged; resolver synchronization from #89/#94 is preserved.

On the loaded arm64 Mac, 12 samples per arm in ABBA order reduce median system CPU from 5.340 to 1.505 seconds (71.8%) and hardware cycles from 24.838 to 11.343 billion (54.3%). Both bootstrap intervals exclude no change. Wall time is 1.805 to 1.890 seconds, a difference within the wide shared-host noise interval. All 352 SDK imports succeed and all 2,093 cache entries are byte-identical. Quiet Linux timings remain unchanged within run variation.

Add a cold/warm module-import benchmark and concurrent symlink/cache-reuse coverage. Align stale hook-cache assertions with format 36 while preserving current-hook, changed-target and removed-target checks.

Validation: 28 cache tests; 141 resolver/cache tests with two existing skips; all 12 Rust targets; native Linux and Darwin CI; scoped-clean Codex P2 review. CI: https://github.com/openclaw/bun/actions/runs/37246173137
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.

1 participant