fix(terminal): atomic env-snapshot replacement to prevent PATH corruption (#38249)

Concurrent terminal calls in one session both source AND rewrite the shared
env snapshot. The per-command re-dump used `export -p > snap` — a non-atomic
truncate-then-write in place (the code even noted "last-writer-wins"). A
concurrent `source snap` could read a half-written file and embed literal
`declare -x` / `export` fragments into PATH, breaking `ls`/`git`/`tr` with
command-not-found until PATH was manually repaired. The corruption persisted
because the malformed env got saved back into the snapshot.

Write to a unique temp file then `mv -f` over the snapshot. `mv`/rename is
atomic on POSIX (same filesystem), so a reader always sees the old-complete or
new-complete file — never a torn one. Applied at both the init_session
bootstrap and the per-command re-dump. `$$` (bash PID) makes the temp name
unique per concurrent process so their temp writes can't collide before the mv.

Salvaged from #38279 by @kyssta-exe (authorship preserved via cherry-pick).
On top of the original I hardened the temp-path quoting: the static path is now
shlex-quoted with `$$` left outside the quotes to expand, so a snapshot path
with a space or a Windows `C:/Users/...` drive letter doesn't break the shell
(matching the existing quoting care for the snapshot path itself; `bash -n`
verified on a spaced path). Added a regression test class (atomic temp+mv used,
not in-place write; per-process-unique temp; static part quoted; bootstrap also
atomic). 22 tests pass, mutation-verified (reverting to the in-place write fails
the atomic tests), ruff clean.

Closes #38249. Supersedes #38267 (serialize-execution lock — heavier and
serializes the spawn-per-call concurrency this fix preserves).
This commit is contained in:
kyssta-exe 2026-06-26 21:47:22 +05:30 • committed by kshitijk4poor
parent 5038678647
commit a54be30b6e
4 changed files with 183 additions and 9 deletions

View file

@ -259,7 +259,6 @@ AUTHOR_MAP = {
"9592417+adam91holt@users.noreply.github.com": "adam91holt",
"kchuang1015@users.noreply.github.com": "kchuang1015",
"maheshthedev@gmail.com": "MaheshtheDev",
"kyssta-exe@users.noreply.github.com": "kyssta-exe",
"shriganesh.patel@gmail.com": "ashishpatel26",
"45688690+fujinice@users.noreply.github.com": "fujinice",
"276689385+carltonawong@users.noreply.github.com": "carltonawong",