Subject: bug#29348: 26.0.50; shr.el heisenbug

From: Devon Sean McCullough <[email-masked]>
Date: Sat, 18 Nov 2017 02:19:29 -0500

Given the same input `shr-render-buffer' and `shr-render-region'
scramble their output about 25% of the time.  Here's a fix:
diff -Bbdu old/shr.el new/shr.el
--- old/shr.el	2017-06-06 16:19:10.000000000 -0400
+++ new/shr.el	2017-11-18 01:35:01.000000000 -0500
@@ -198,6 +198,30 @@
       (set-keymap-parent map image-map))
     map))
 
+(eval-when (compile eval)
+  (defmacro shr-with-temp-window (&rest body)
+    "Temporarily give the current buffer some window and evaluate BODY there like progn."
+    ;; Avoid the `save-window-excursion' heisenbug
+    ;; which sporadically clobbers some other buffer's point
+    ;; jumbling `shr-render-buffer' and `shr-render-region' output.
+    (let ((c (gensym "WCONFIG"))
+	  (p (gensym "POINT")))
+      `(let* ((,c (current-window-configuration))
+	      (,p (with-current-buffer (window-buffer (selected-window))
+		    (point)))
+	      ;; Inhibit any `set-window-buffer' hooks:
+	      window-scroll-functions
+	      window-configuration-change-hook)
+	 (unwind-protect
+	     (progn
+	       ;; Avoid errors if the selected window is strongly dedicated.
+	       (set-window-dedicated-p nil nil)
+	       (set-window-buffer nil (current-buffer))
+	       .,body)
+	   (set-window-configuration ,c)
+	   (with-current-buffer (window-buffer (selected-window))
+	     (set-window-point (selected-window) (goto-char ,p))))))))
+
 ;; Public functions and commands.
 (declare-function libxml-parse-html-region "xml.c"
 		  (start end &optional base-url discard-comments))
@@ -539,14 +563,10 @@
 (defun shr-pixel-column ()
   (if (not shr-use-fonts)
       (current-column)
-    (if (not (get-buffer-window (current-buffer)))
-	(save-window-excursion
-          ;; Avoid errors if the selected window is a dedicated one,
-          ;; and they just want to insert a document into it.
-          (set-window-dedicated-p nil nil)
-	  (set-window-buffer nil (current-buffer))
-	  (car (window-text-pixel-size nil (line-beginning-position) (point))))
-      (car (window-text-pixel-size nil (line-beginning-position) (point))))))
+    (if (get-buffer-window)
+	(car (window-text-pixel-size nil (line-beginning-position) (point)))
+      (shr-with-temp-window
+	(car (window-text-pixel-size nil (line-beginning-position) (point)))))))
 
 (defun shr-pixel-region ()
   (- (shr-pixel-column)
@@ -2228,13 +2248,9 @@
 	    (forward-line 1))
 	  max))
     (if (get-buffer-window)
-	(car (window-text-pixel-size nil (point-min) (point-max)))
-      (save-window-excursion
-        ;; Avoid errors if the selected window is a dedicated one,
-        ;; and they just want to insert a document into it.
-        (set-window-dedicated-p nil nil)
-	(set-window-buffer nil (current-buffer))
-	(car (window-text-pixel-size nil (point-min) (point-max)))))))
+	(car (window-text-pixel-size))
+      (shr-with-temp-window
+	(car (window-text-pixel-size))))))
 
 (defun shr-render-td (dom width fill)
   (let ((cache (intern (format "shr-td-cache-%s-%s" width fill))))
@@ -2275,11 +2291,7 @@
       (let ((shr-internal-width width)
 	    (shr-indentation 0))
 	(shr-descend dom))
-      (save-window-excursion
-        ;; Avoid errors if the selected window is a dedicated one,
-        ;; and they just want to insert a document into it.
-        (set-window-dedicated-p nil nil)
-	(set-window-buffer nil (current-buffer))
+      (shr-with-temp-window
 	(unless fill
 	  (setq natural-width
 		(or (dom-attr dom 'shr-td-cache-natural)

In GNU Emacs 26.0.50 (build 1, x86_64-apple-darwin13.4.0, NS appkit-1265.21 Version 10.9.5 (Build 13F1911))
 of 2017-06-07 built on builder10-9.local
Windowing system distributor 'Apple', version 10.3.1404
Recent messages:
Warning: arch-dependent data dir ’/Users/build/workspace/Emacs-Multi-Build/label/mavericks/emacs-source/nextstep/Emacs.app/Contents/MacOS/libexec/’: No such file or directory

For information about GNU Emacs and the GNU system, type C-h C-a.

Configured using:
 'configure --with-ns '--enable-locallisppath=/Library/Application
 Support/Emacs/${version}/site-lisp:/Library/Application
 Support/Emacs/site-lisp' --with-modules'

Configured features:
NOTIFY ACL GNUTLS LIBXML2 ZLIB TOOLKIT_SCROLL_BARS NS MODULES

Important settings:
  value of $LANG: en_US.UTF-8
  locale-coding-system: utf-8-unix

Major mode: Lisp Interaction

Minor modes in effect:
  tooltip-mode: t
  global-eldoc-mode: t
  eldoc-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  tool-bar-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  line-number-mode: t
  transient-mark-mode: t

Load-path shadows:
None found.

Features:
(shadow sort mail-extr emacsbug message subr-x puny seq byte-opt gv
bytecomp byte-compile cconv cl-loaddefs cl-lib dired dired-loaddefs
format-spec rfc822 mml easymenu mml-sec password-cache epa derived epg
epg-config gnus-util rmail rmail-loaddefs mm-decode mm-bodies mm-encode
mail-parse rfc2231 mailabbrev gmm-utils mailheader sendmail rfc2047
rfc2045 ietf-drums mm-util mail-prsvr mail-utils time-date tooltip eldoc
electric uniquify ediff-hook vc-hooks lisp-float-type mwheel term/ns-win
ns-win ucs-normalize mule-util term/common-win tool-bar dnd fontset
image regexp-opt fringe tabulated-list replace newcomment text-mode
elisp-mode lisp-mode prog-mode register page menu-bar rfn-eshadow
isearch timer select scroll-bar mouse jit-lock font-lock syntax facemenu
font-core term/tty-colors frame cl-generic cham georgian utf-8-lang
misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms
cp51932 hebrew greek romanian slovak czech european ethiopic indian
cyrillic chinese composite charscript charprop case-table epa-hook
jka-cmpr-hook help simple abbrev obarray minibuffer cl-preloaded nadvice
loaddefs button faces cus-face macroexp files text-properties overlay
sha1 md5 base64 format env code-pages mule custom widget
hashtable-print-readable backquote kqueue cocoa ns multi-tty
make-network-process emacs)

Memory information:
((conses 16 203281 5816)
 (symbols 48 19810 1)
 (miscs 40 43 125)
 (strings 32 17913 6360)
 (string-bytes 1 581057)
 (vectors 16 34820)
 (vector-slots 8 694299 11533)
 (floats 8 48 182)
 (intervals 56 204 0)
 (buffers 976 11))