bug#81562: [PATCH] Restore current_buffer when window_text_pixel_size fails
Maxim Wayne <[email protected]> Wed, 5 Aug 2026 20:26:45 +0800
| Newsgroups | gmane.emacs.bugs |
|---|---|
| Message-ID | <CADtsJB2b1WTQjLWZJjtpU3ap6h1XKQ6iiPZXf7juUfN5t9Djpw@mail.gmail.com> |
The window-text-pixel-size function temporarily switches the current_buffer pointer; if the function fails, the pointer is not switched back. To reproduce: When current_buffer = buf_a while the window displays buf_b, giving a cons whose cdr is not an integer as the FROM argument to window-text-pixel-size, the function fails and current_buffer doesn't switch back to buf_a. The included test fails on Emacs 30.2 and passes on the patched code. Please see the attachment for the patch. The patch is against current master (commit 602cde3).
0001-1.patch
(application/octet-stream, 2.9 KB)
From ce3d004ba030d7fb3086842b33f9bb973e8a5e44 Mon Sep 17 00:00:00 2001 From: SkyCanvas <[email protected]> Date: Tue, 4 Aug 2026 21:17:47 +0800 Subject: [PATCH] Restore current_buffer when window_text_pixel_size fails In the b != current_buffer branch, if window_text_pixel_size encounters an error (such as receiving an argument of the wrong type), the current_buffer pointer remains at b and is not correctly switched back. The specpdl unwind mechanism effectively resolves this issue. The call to window_text_pixel_size is now wrapped between two specpdl statements. This ensures that the current_buffer pointer is restored regardless of whether the function exits normally or an exception occurs. * src/xdisp.c (Fwindow_text_pixel_size): Use the unwind mechanism instead of direct pointer manipulation. * test/src/xdisp-tests.el (xdisp-tests-window-text-pixel-size-buffer-restore): Add exception testing. --- src/xdisp.c | 11 +++++------ test/src/xdisp-tests.el | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index caea8e7..ada3ef5 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -12107,20 +12107,19 @@ DEFUN ("window-text-pixel-size", Fwindow_text_pixel_size, Swindow_text_pixel_siz { struct window *w = decode_live_window (window); struct buffer *b = XBUFFER (w->contents); - struct buffer *old_b = NULL; Lisp_Object value; + specpdl_ref count = SPECPDL_INDEX (); if (b != current_buffer) { - old_b = current_buffer; + record_unwind_current_buffer (); set_buffer_internal_1 (b); } - value = window_text_pixel_size (window, from, to, x_limit, y_limit, mode_lines, - ignore_line_at_end); + value = window_text_pixel_size (window, from, to, x_limit, y_limit, + mode_lines, ignore_line_at_end); - if (old_b) - set_buffer_internal_1 (old_b); + unbind_to (count, Qnil); return value; } diff --git a/test/src/xdisp-tests.el b/test/src/xdisp-tests.el index 8eb5725..e6da534 100644 --- a/test/src/xdisp-tests.el +++ b/test/src/xdisp-tests.el @@ -213,4 +213,21 @@ xdisp-test-format-mode-line (should (equal m1 m2)) (should (equal s1 s2))))) +(ert-deftest xdisp-tests-window-text-pixel-size-buffer-restore () + (let ((buf-a (generate-new-buffer "buf-a")) + (buf-b (generate-new-buffer "buf-b"))) + (unwind-protect + (progn + (with-current-buffer buf-b + (insert "test content for window-text-pixel-size")) + (set-window-buffer (selected-window) buf-b) + (set-buffer buf-a) + (should-error + (window-text-pixel-size (selected-window) + (cons 1 "not-a-fixnum") + nil nil nil nil nil)) + (should (eq (current-buffer) buf-a))) + (ignore-errors (kill-buffer buf-a)) + (ignore-errors (kill-buffer buf-b))))) + ;;; xdisp-tests.el ends here -- 2.55.0