Skip to content

Stop the shim silently going deaf mid-command#3

Open
lai0xn wants to merge 1 commit into
edaywalid:mainfrom
lai0xn:fix/shim-stops-journaling
Open

Stop the shim silently going deaf mid-command#3
lai0xn wants to merge 1 commit into
edaywalid:mainfrom
lai0xn:fix/shim-stops-journaling

Conversation

@lai0xn

@lai0xn lai0xn commented Jul 26, 2026

Copy link
Copy Markdown

Two bugs where the shim stops journaling with no sign to the user, so undo says "nothing to undo" for changes it should have captured.

rmdir() leaks the reentrancy guard. It sets in_shim = 1 on entry but only clears it on the success path, so any failed rmdir leaves it set for the rest of the process — every later unlink/open/rename sees armed() == false and goes unrecorded. rmdir a b with a non-empty a is enough to lose b. Every other interposed function clears it on all paths.

The mod dedup table never resets between sessions. It's process-global with no session key. Fine for a fresh child per command, wrong under UNDO_CAPTURE_SHELL=1 where the shim lives in the shell across every command: a file backed up once is skipped forever after, so later edits are unrecoverable. Now keyed on the session dir.

Minor: undo run returned 255 for signal deaths (ExitCode() is -1); now 128+signal.

e2e cases 19 and 20 both fail on the old shim. Case 20 uses python3 to drive the one-process-two-sessions path, since bash's export doesn't reliably update the C environ the shim reads; it skips where python3 is absent so the musl job doesn't break.

Two paths made the shim stop journaling without any sign to the user,
which is the worst failure mode this tool has: `undo` reports "nothing
to undo" for changes it should have captured.

rmdir() set the reentrancy guard on entry but only cleared it on the
success path, so any failed rmdir (a non-empty directory, ENOENT) left
in_shim set for the rest of the process. Everything that process did
afterwards saw armed() == false and went unrecorded. `rmdir a b` with a
non-empty `a` was enough to lose `b`.

The mod dedup table was keyed on nothing, so it persisted across
sessions in a process that outlives one command -- exactly the
UNDO_CAPTURE_SHELL=1 setup, where the shim lives in the shell itself.
A file written in one command suppressed its own backup in every later
one. Reset the table when the session directory changes.

Also propagate signal deaths from `undo run` as 128+signal instead of
letting ExitCode()'s -1 become a bare 255.
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