Skip to content

Abort compile finalization when a finish hook kills the buffer - #601

Merged
dakra merged 1 commit into
mainfrom
fix/compile-finalize-killed-buffer
Aug 5, 2026
Merged

dakra merged 1 commit into
mainfrom
fix/compile-finalize-killed-buffer

Conversation

@dakra

@dakra dakra commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Reported downstream in doomemacs/core#8862: with Doom's (ghostel +everywhere) and (popup +defaults), doom/reload installed a buffer-local compilation-finish-functions entry that deleted the compile popup window, and the popup rule's :ttl 0 then killed the compile buffer while ghostel-compile--finalize was still running.

When the current buffer is killed mid-with-current-buffer, Emacs quietly makes another buffer current, so the rest of finalize operated on an unrelated buffer: it switched that buffer's major mode, inserted the Compilation finished at ... footer into it, and finally signaled No such live buffer #<killed buffer> from get-buffer-window-list. Doom no longer closes that window as of doomemacs/core@f6f0769, but any finish function or popup/shackle-style kill-on-window-delete rule can still trigger the same corruption.

Fix: a new ghostel-compile--reenter-or-abort guard runs after every foreign-callback point in finalize — each buffer-local finish function, the (funcall target-mode) mode switch (mode hooks), and the global compilation-finish-functions run. It aborts finalization if the buffer died and re-enters it explicitly in case a callback left another buffer current. Aborting is safe at all three points: the run is already marked finalized and the terminal torn down before the first callback fires.

Most of the lisp/ghostel-compile.el diff is a mechanical reindent from the new catch form; review with whitespace ignored to see the ~25 real lines.

Regression tests (plain elisp, no native module) cover all three kill points and assert the victim buffer keeps its major mode and contents, later finish functions don't run against the dead buffer, and no error is signaled. All three fail on main with exactly the reported corruption.

A compilation-finish-function or a mode hook of the finished major
mode may kill the compile buffer mid-finalize (e.g. a popup rule that
kills the buffer when its window is deleted).  Emacs then quietly
makes another buffer current, and the rest of ghostel-compile--finalize
would switch that unrelated buffer's major mode, insert the compilation
footer into it, and finally signal "No such live buffer" from
get-buffer-window-list.

Guard every foreign-callback point — each buffer-local finish function,
the major-mode switch, and the global compilation-finish-functions run —
with ghostel-compile--reenter-or-abort: abort finalization if the buffer
died, and re-enter it explicitly in case a callback left another buffer
current.
@dakra
dakra merged commit ba802e9 into main Aug 5, 2026
29 checks passed
@dakra
dakra deleted the fix/compile-finalize-killed-buffer branch August 5, 2026 08:10

This branch was previously deployed

1 inactive deployment
github-pages — ba802e91 Deployed Aug 5, 2026 by dakra via deploy #146
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