mirror of
https://github.com/oven-sh/bun
synced 2026-02-27 20:17:23 +01:00
## Summary - Fixes use-after-free (ASAN use-after-poison) when shell builtins (`ls`, `touch`, `mkdir`, `cp`) run inside command substitution `$(...)` and encounter errors (e.g., permission denied) - The `output_waiting` and `output_done` counters in the builtin exec state went out of sync because `output_waiting` was only incremented for async IO operations, while `output_done` was always incremented - In command substitution, stdout is `.pipe` (sync) and stderr is `.fd` (async), so a single OutputTask completing both writes could satisfy the done condition while another OutputTask's async stderr write was still pending in the IOWriter The fix moves `output_waiting += 1` before the `needsIO()` check in all four affected builtins so it's always incremented, matching `output_done`. ## Test plan - [x] `echo $(ls /tmp/*)` — no ASAN errors (previously crashed with use-after-poison) - [x] `echo $(touch /root/a /root/b ...)` — no ASAN errors - [x] `echo $(mkdir /root/a /root/b ...)` — no ASAN errors - [x] `ls /nonexistent` — still reports error and exits with code 1 - [x] `echo $(ls /tmp)` — still captures output correctly - [x] Existing shell test suite: 292 pass, 52 fail (pre-existing), 83 todo — no regressions 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>