bug#81562: [PATCH] Restore current_buffer when window_text_pixel_size fails

Maxim Wayne <[email protected]>
Newsgroups gmane.emacs.bugs
Message-ID <CADtsJB039puj-1mSKGpvaB=63=-qSCKjO=PJMXr7s_H5dxLGWg@mail.gmail.com>
Thanks.

I've reworked the patch to validate the arguments up front, as you
suggested.  FROM, TO, X-LIMIT, Y-LIMIT and MODE-LINES are now checked
with the CHECK_* macros at the beginning of Fwindow_text_pixel_size,
before any buffer switch.

For MODE-LINES, my check limits the value to the three symbols:
mode-line, tab-line and header-line -- please tell me if you prefer
checking only the type.

The patch adds two tests: one verifies that an invalid FROM argument
signals an error before the buffer switch, the other covers the rest
of the new checks.  Both fail on Emacs 30.2 and pass with the patch
applied.

The patch is attached; it is against current master (commit
cb22cfe1414).

On Thu, Aug 6, 2026 at 12:25 PM Eli Zaretskii <[email protected]> wrote:

> > From: Maxim Wayne <[email protected]>
> > Date: Wed, 5 Aug 2026 20:26:45 +0800
> >
> > 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).
>
> Thanks, but this is not the correct solution.  Our conventions are to
> validate the arguments of the primitives up front, using the various
> CHECK_* macros (like CHECK_NUMBER, CHECK_BUFFER, etc.), and if those
> validations fail, signal an error before performing any significant
> processing (including switching to another buffer).  It is true that
> this primitive fails to perform such checks, but the correct solution
> is to add them, not to recover from errors the low-level code might
> signal due to invalid arguments.
>
> Would you like to submit a patch along those lines?
>
0001-Validate-arguments-of-window-text-pixel-size-up-fron.patch (application/octet-stream, 4.6 KB)
From 208c486db2d54016ebea6f8caaa34ecc84ee4f0e Mon Sep 17 00:00:00 2001
From: SkyCanvas <[email protected]>
Date: Sun, 16 Aug 2026 22:03:05 +0800
Subject: [PATCH] Validate arguments of window-text-pixel-size up front

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.

FROM, TO, X-LIMIT, Y-LIMIT and MODE-LINES are now checked with
CHECK_* macros before the buffer switch.

* src/xdisp.c (Fwindow_text_pixel_size): Validate arguments before
calling window_text_pixel_size.

* test/src/xdisp-tests.el
(xdisp-tests--window-text-pixel-size-args-before-switch)
(xdisp-tests--window-text-pixel-size-invalid-args): New tests.
---
 src/xdisp.c             | 30 +++++++++++++++++++++++++++
 test/src/xdisp-tests.el | 46 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+)

diff --git a/src/xdisp.c b/src/xdisp.c
index beb8d980ee3..12f8627c650 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -12128,6 +12128,36 @@ DEFUN ("window-text-pixel-size", Fwindow_text_pixel_size, Swindow_text_pixel_siz
   struct buffer *old_b = NULL;
   Lisp_Object value;
 
+  if (!NILP (from) && !EQ (from, Qt))
+    {
+      if (CONSP (from))
+	{
+	  CHECK_TYPE (INTEGERP (XCAR (from)) || MARKERP (XCAR (from)),
+		      Qinteger_or_marker_p, XCAR (from));
+	  CHECK_FIXNUM (XCDR (from));
+	}
+      else
+	CHECK_TYPE (INTEGERP (from) || MARKERP (from),
+		    Qinteger_or_marker_p, from);
+    }
+
+  if (!NILP (to) && !EQ (to, Qt))
+    CHECK_TYPE (INTEGERP (to) || MARKERP (to), Qinteger_or_marker_p, to);
+
+  if (!NILP (x_limit) && !EQ (x_limit, Qt))
+    CHECK_FIXNAT (x_limit);
+
+  if (!NILP (y_limit))
+    CHECK_FIXNAT (y_limit);
+
+  if (!NILP (mode_lines) && !EQ (mode_lines, Qt))
+    {
+      CHECK_SYMBOL (mode_lines);
+      if (!EQ (mode_lines, Qmode_line) && !EQ (mode_lines, Qtab_line)
+	  && !EQ (mode_lines, Qheader_line))
+        error ("MODE-LINES must be mode-line, tab-line or header-line");
+    }
+
   if (b != current_buffer)
     {
       old_b = current_buffer;
diff --git a/test/src/xdisp-tests.el b/test/src/xdisp-tests.el
index 8eb57253972..3722dadb1cc 100644
--- a/test/src/xdisp-tests.el
+++ b/test/src/xdisp-tests.el
@@ -213,4 +213,50 @@ xdisp-test-format-mode-line
       (should (equal m1 m2))
       (should (equal s1 s2)))))
 
+(ert-deftest xdisp-tests--window-text-pixel-size-args-before-switch ()
+  "Invalid arguments must be rejected before switching to WINDOW's buffer."
+  (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)
+           :type 'wrong-type-argument)
+          (should (eq (current-buffer) buf-a)))
+      (ignore-errors (kill-buffer buf-a))
+      (ignore-errors (kill-buffer buf-b)))))
+
+(ert-deftest xdisp-tests--window-text-pixel-size-invalid-args ()
+  ;; FROM must be nil, t, a position (integer or marker), or a cons
+  ;; (POSITION . VERTICAL-OFFSET) where VERTICAL-OFFSET is a fixnum.
+  (should-error (window-text-pixel-size nil "foo")
+                :type 'wrong-type-argument)
+  (should-error (window-text-pixel-size nil '("foo" . 1))
+                :type 'wrong-type-argument)
+  (should-error (window-text-pixel-size nil '(1 . "foo"))
+                :type 'wrong-type-argument)
+  ;; TO must be nil, t, or a position.
+  (should-error (window-text-pixel-size nil nil "foo")
+                :type 'wrong-type-argument)
+  ;; X-LIMIT must be nil, t, or a nonnegative fixnum.
+  (should-error (window-text-pixel-size nil nil nil "foo")
+                :type 'wrong-type-argument)
+  (should-error (window-text-pixel-size nil nil nil -1)
+                :type 'wrong-type-argument)
+  ;; Y-LIMIT must be nil or a nonnegative fixnum; unlike X-LIMIT,
+  ;; t is not valid.
+  (should-error (window-text-pixel-size nil nil nil nil t)
+                :type 'wrong-type-argument)
+  ;; MODE-LINES must be nil, t, or one of the three line symbols.
+  (should-error (window-text-pixel-size nil nil nil nil nil 'mod-line))
+  ;; Valid arguments must still be accepted.
+  (should (consp (window-text-pixel-size nil '(1 . 0))))
+  (should (consp (window-text-pixel-size nil nil nil t nil 'mode-line))))
+
 ;;; xdisp-tests.el ends here
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.