Repository navigation
Conversation
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.
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. 🧰 Additional context used📚 Code guidelines (1)No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (3)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review. WalkthroughThe resolver entry cache now uses guarded access instead of ChangesResolver cache and Miri coverage
Suggested reviewers: Priority: ⬇️ Low Merge Risk: ⚪ Minimal · up to No actionable merge-blocking risk is identified; the change is ready to merge after normal checks. Security Architecture ReviewSecurity architecture risk: ⚪ Minimal · up to The change strengthens synchronization without expanding privileges. The inspected execution and failure paths preserve existing controls, and no material security regression was identified. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
Comment |
Store the parts of the published path in an AtomicPtr and an AtomicUsize. The fill writes the length and then the pointer under the per-entry mutex, and the Release store of the pointer publishes both. The field is Sync without the help of `unsafe impl Sync for Entry`, which now covers `cache` only. The size of Entry does not change. An in-place refresh already keeps the slot's `dir`, so the store of `dir` into a recycled entry wrote the same value while other threads read it. Replace it with a debug assertion and borrow the recycled entry as shared. The unit test now runs the contended fill eight times and checks that a reader never sees a published pointer without its length. Under Miri it fails on every one of 32 seeds when the mutex is removed, when the two stores are swapped, or when the pointer is stored or loaded with Relaxed. Use the same Miri list position and the same ignore reason as #44539, so the two changes do not conflict in those lines.
Entry.cachecan be rewritten while another resolver thread copies it. The per-entry mutex serializes writers, but thekind()/symlink()fast paths readCell<EntryCache>without that lock.need_statpublishes a lazy fill; it cannot protect an already-started reader from subsequent symlink fills, fd updates, or re-stats. A tornInternedpointer/length can reach path parsing.Use the existing
Guarded<EntryCache>for complete snapshots and field updates, preserving the outer entry mutex's stat/fd lifecycle scopes and the outer-entry → cache lock order. Remove the manualEntrySend/Sync implementations. Add concurrent symlink-fill and re-stat tests to the Miri runner; the existing data-URL tests remain enabled normally and are ignored only under Miri because they call native SIMD functions.This follows up the mutable-cache race explicitly left open by #37274. It is complementary to #40258, which protects the separate
abs_pathfield. The broader #38365 realpath rewrite also retainsCell<EntryCache>and unlocked fast readers at the inspected head; no upstream mutable-cache fix was found.Validation used the OpenClaw Bun fork, whose prepatch
fs.rs,Guarded, andMutexsources are identical to this upstream base:Cell<EntryCache>::setinset_cache_symlinkracingCell::getinsymlink/cache. Patched fill and re-stat tests both pass TSan and Miri. TSan rebuilt std with unwind; unrelated data-URL tests were omitted from that temporary native diagnostic to avoid their SIMD link dependencies, then restored.The original consumer native crash has not been directly reproduced; the TSan-reported cache race is the demonstrated defect. A more aggressive symlink-churn fixture still sometimes returns a directory-only resolved path and throws module-not-found on both baseline and patched release binaries. That remaining resolution failure, the separate
abs_pathrace, and the existing cached-fd close/ownership protocol are not claimed fixed here.Merged fork implementation: openclaw#89 (
d894d7fcbf). Both Linux x64 and Darwin arm64 native CI lanes passed on the final fork head: https://github.com/openclaw/bun/actions/runs/37114526179. Independent P2 review of this upstream candidate is scoped-clean.