Skip to content

persp-current-buffers*: read frame-global buffers without switching perspectives - #233

Merged
gcv merged 1 commit into
nex3:masterfrom
aiba:avoid-persp-switch-in-current-buffers
Jul 14, 2026
Merged

persp-current-buffers*: read frame-global buffers without switching perspectives#233
gcv merged 1 commit into
nex3:masterfrom
aiba:avoid-persp-switch-in-current-buffers

Conversation

@aiba

@aiba aiba commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Problem

persp-current-buffers* with INCLUDE-GLOBAL reads the frame global perspective's buffer list via with-perspective, which runs persp-switch twice (there and back). Each switch restores a window configuration. Callers of persp-current-buffers* / persp-is-current-buffer / persp-buffer-filter reasonably treat them as pure predicates, so this side effect is surprising — and it turns out to be fatal in one realistic scenario:

Emacs evaluates menu-bar :enable forms during redisplay (update_menu_bar → menu_item_eval_property). If such a form reaches a perspective buffer predicate (in my case: CIDER's menu :enable (cider-connected-p) → sesman session lookup → a sesman-to-perspective filter → persp-is-current-buffer buf t), the with-perspective round-trip executes delete-other-windows mid-redisplay, which calls adjust_frame_glyphs and reallocates the window's glyph matrices while display_line holds pointers into them. Emacs 31.0.90 segfaults 100% reproducibly (set_cursor_from_row computes a garbage w->cursor.vpos from a stale row pointer; the next display_line indexes ~340 GB out of bounds). I debugged this under lldb down to the exact instructions, and caught the persp-switch → delete-other-windows → adjust_glyph_matrix chain live with a breakpoint while redisplay_internal was on the stack. A hardening report to bug-gnu-emacs is in flight, but the crash is trivially avoided by not switching perspectives here at all.

Fix

Read the frame global perspective's buffer list directly from perspectives-hash. persp-get-scratch-buffer already accepts the perspective name, so the scratch-buffer exclusion behaves identically. This follows the same approach as #226 (persp-maybe-kill-buffer: avoid switching perspectives).

Bonus fix: the previous code returned the global perspective's live buffer list as the shared tail of append, exposing it to the destructive delete-dups; copy-sequence now protects it.

Testing

make test: 32/33 pass, matching pristine HEAD on the same Emacs — the one failure (basic-persp-window-prev-buffers) pre-exists on master under Emacs 31.0.90 batch mode and is unrelated (verified by running the suite on an unpatched checkout). Byte-compiles with no new warnings. The equivalent change applied at the configuration level (checking persp-buffers membership directly, bypassing the with-perspective round-trip) eliminates the segfault in the originally crashing CIDER + perspective session.

🤖 Generated with Claude Code

https://claude.ai/code/session_01F3SLHGSnQuGu2QukBqs1wd

with-perspective runs persp-switch (twice — there and back), and each
switch restores a window configuration. Callers of
persp-current-buffers* / persp-is-current-buffer / persp-buffer-filter
treat them as pure predicates, so this side effect is surprising — and
fatal when a predicate runs inside redisplay: a menu-bar item's :enable
form that consults a buffer predicate (e.g. CIDER's menu via a
sesman-to-perspective filter) triggers delete-other-windows from within
update_menu_bar, reallocating the window's glyph matrices while
display_line iterates over them. Emacs 31.0.90 segfaults in
set_cursor_from_row / display_line (report to bug-gnu-emacs in flight).

Read the frame global perspective's buffer list directly from
perspectives-hash instead. persp-get-scratch-buffer already accepts the
perspective name, so behavior is unchanged. copy-sequence keeps the
destructive delete-dups off the global perspective's live buffer list,
which the previous code exposed as the shared tail of append.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3SLHGSnQuGu2QukBqs1wd
@gcv
gcv merged commit 6cf7158 into nex3:master Jul 14, 2026
8 checks passed
@gcv

gcv commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Looks solid. That’s some impressive lldb work by Claude. Merged.

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.

2 participants