Subject: Re: bug#61504: 29.0.60; executing byte-code from previous build causes SIGSEGV crash

From: Gregory Heytings <[email-masked]>
Date: Tue, 14 Feb 2023 09:29:32 +0000

>
> There seems to be a byte-code change between versions 
> 0ec0a610ed226419269f519021cbe8fb2dde2ed5 (old) and 
> a4aa32bdfff7aaf54efbacbb04b7f2b52fef92a7 (new) which causes the new 
> version to crash with SIGSEGV when executing certain code from an .elc 
> built using the old version. Recompiling the file with the new version 
> causes the new .elc to work correctly.
>

The bytecode did not change, but the byte codes generated by the 
save-restriction form did change.

Now that I think of it again, it is possible make that change while 
preserving backward compatibility.

Eli, what do you think of the attached patch?  It restores the 'unbind 1' 
at the end of save-restriction, and puts the two data elements into a cons 
instead of pushing them separately.  (Of course this passes make and make 
check, with and without native compilation.)
From 85f4a2851514fad981b74abe14b833196d5987b0 Mon Sep 17 00:00:00 2001
From: Gregory Heytings <[email-masked]>
Date: Tue, 14 Feb 2023 09:22:22 +0000
Subject: [PATCH] Improve backward compatibility of save-restriction

* src/editfns.c (save_restriction_and_narrowing_locks_restore):
New function, combining 'save_restriction_restore' and
'narrowing_locks_restore'.
(narrowing_locks_restore): Make static.
(Fsave_restriction): Use the new function instead of the two ones
it combines.

* src/lisp.h: Make the new function externally visible.

* src/bytecode.c (exec_byte_code): Use the new function instead of
the two ones it combines.

* src/comp.c (helper_save_restriction): Use the new function
instead of the two ones it combines.

* lisp/emacs-lisp/bytecomp.el (byte-compile-save-restriction):
Decrement unbinding count.
---
 lisp/emacs-lisp/bytecomp.el |  2 +-
 src/bytecode.c              |  7 +++----
 src/comp.c                  |  7 +++----
 src/editfns.c               | 14 +++++++++++---
 src/lisp.h                  |  2 +-
 5 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index c6cda6b588a..5df1205869c 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -4900,7 +4900,7 @@ byte-compile-save-excursion
 (defun byte-compile-save-restriction (form)
   (byte-compile-out 'byte-save-restriction 0)
   (byte-compile-body-do-effect (cdr form))
-  (byte-compile-out 'byte-unbind 2))
+  (byte-compile-out 'byte-unbind 1))
 
 (defun byte-compile-save-current-buffer (form)
   (byte-compile-out 'byte-save-current-buffer 0)
diff --git a/src/bytecode.c b/src/bytecode.c
index 8e214560f30..ca7ae4766e1 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -940,10 +940,9 @@ #define DEFINE(name, value) [name] = &&insn_ ## name,
 	  }
 
 	CASE (Bsave_restriction):
-	  record_unwind_protect (save_restriction_restore,
-				 save_restriction_save ());
-	  record_unwind_protect (narrowing_locks_restore,
-				 narrowing_locks_save ());
+	  record_unwind_protect (save_restriction_and_narrowing_locks_restore,
+				 Fcons (save_restriction_save (),
+					narrowing_locks_save ()));
 	  NEXT;
 
 	CASE (Bcatch):		/* Obsolete since 25.  */
diff --git a/src/comp.c b/src/comp.c
index 0e2dfd3913b..fe2c9b054b6 100644
--- a/src/comp.c
+++ b/src/comp.c
@@ -5061,10 +5061,9 @@ helper_unbind_n (Lisp_Object n)
 static void
 helper_save_restriction (void)
 {
-  record_unwind_protect (save_restriction_restore,
-			 save_restriction_save ());
-  record_unwind_protect (narrowing_locks_restore,
-			 narrowing_locks_save ());
+  record_unwind_protect (save_restriction_and_narrowing_locks_restore,
+			 Fcons (save_restriction_save (),
+				narrowing_locks_save ()));
 }
 
 static bool
diff --git a/src/editfns.c b/src/editfns.c
index ce133785e0b..dbcc5728dda 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -2804,7 +2804,7 @@ narrowing_locks_save (void)
   return Fcons (buf, Fcopy_sequence (locks));
 }
 
-void
+static void
 narrowing_locks_restore (Lisp_Object buf_and_saved_locks)
 {
   Lisp_Object buf = XCAR (buf_and_saved_locks);
@@ -3068,6 +3068,13 @@ save_restriction_restore (Lisp_Object data)
     set_buffer_internal (cur);
 }
 
+void
+save_restriction_and_narrowing_locks_restore (Lisp_Object data)
+{
+  save_restriction_restore (XCAR (data));
+  narrowing_locks_restore (XCDR (data));
+}
+
 DEFUN ("save-restriction", Fsave_restriction, Ssave_restriction, 0, UNEVALLED, 0,
        doc: /* Execute BODY, saving and restoring current buffer's restrictions.
 The buffer's restrictions make parts of the beginning and end invisible.
@@ -3091,8 +3098,9 @@ DEFUN ("save-restriction", Fsave_restriction, Ssave_restriction, 0, UNEVALLED, 0
   register Lisp_Object val;
   specpdl_ref count = SPECPDL_INDEX ();
 
-  record_unwind_protect (save_restriction_restore, save_restriction_save ());
-  record_unwind_protect (narrowing_locks_restore, narrowing_locks_save ());
+  record_unwind_protect (save_restriction_and_narrowing_locks_restore,
+			 Fcons (save_restriction_save (),
+				narrowing_locks_save ()));
   val = Fprogn (body);
   return unbind_to (count, val);
 }
diff --git a/src/lisp.h b/src/lisp.h
index 93197d38176..a86a2e823f9 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4685,7 +4685,7 @@ XMODULE_FUNCTION (Lisp_Object o)
 extern Lisp_Object save_restriction_save (void);
 extern void save_restriction_restore (Lisp_Object);
 extern Lisp_Object narrowing_locks_save (void);
-extern void narrowing_locks_restore (Lisp_Object);
+extern void save_restriction_and_narrowing_locks_restore (Lisp_Object);
 extern Lisp_Object make_buffer_string (ptrdiff_t, ptrdiff_t, bool);
 extern Lisp_Object make_buffer_string_both (ptrdiff_t, ptrdiff_t, ptrdiff_t,
 					    ptrdiff_t, bool);
-- 
2.39.0