Subject: Re: `unwind-protect' cleanup form is not executed if body dies in stack overflow

From: Paul Eggert <[email-masked]>
Date: Sun, 14 Oct 2018 10:02:59 -0700

Thanks for the bug report; I installed the attached to fix it. The problem with 
your test case was neither C stack overflow nor failure to unwind the Lisp 
stack: it was failure to restore the Lisp evaluation depth (which is a separate 
thing from the Lisp stack size).

By the way, why are there two different limits? That slows the interpreter down 
a bit.  Why don't we simply have a limit for the Lisp stack size? Every time 
lisp_eval_depth grows, the stack size grows, so limiting the stack limits the 
evaluation depth for free. If we had done things this way, the interpreter would 
be a bit faster and this bug would never have occurred.
>From 5dfbdff57be6e93efe79f9b07e8b6383ec02959a Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Sun, 14 Oct 2018 09:51:32 -0700
Subject: [PATCH] Fix lisp_eval_depth in unwind-protect cleanup

Problem reported by Paul Pogonyshev (Bug#33034).
* src/lisp.h (union specbinding): New member unwind.eval_depth.
* src/eval.c (record_unwind_protect, set_unwind_protect): Set it.
(do_one_unbind): Use it.
---
 src/eval.c | 3 +++
 src/lisp.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/src/eval.c b/src/eval.c
index 42c275de6b..a51d0c9083 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -3429,6 +3429,7 @@ record_unwind_protect (void (*function) (Lisp_Object), Lisp_Object arg)
   specpdl_ptr->unwind.kind = SPECPDL_UNWIND;
   specpdl_ptr->unwind.func = function;
   specpdl_ptr->unwind.arg = arg;
+  specpdl_ptr->unwind.eval_depth = lisp_eval_depth;
   grow_specpdl ();
 }
 
@@ -3501,6 +3502,7 @@ do_one_unbind (union specbinding *this_binding, bool unwinding,
   switch (this_binding->kind)
     {
     case SPECPDL_UNWIND:
+      lisp_eval_depth = this_binding->unwind.eval_depth;
       this_binding->unwind.func (this_binding->unwind.arg);
       break;
     case SPECPDL_UNWIND_ARRAY:
@@ -3595,6 +3597,7 @@ set_unwind_protect (ptrdiff_t count, void (*func) (Lisp_Object),
   p->unwind.kind = SPECPDL_UNWIND;
   p->unwind.func = func;
   p->unwind.arg = arg;
+  p->unwind.eval_depth = lisp_eval_depth;
 }
 
 void
diff --git a/src/lisp.h b/src/lisp.h
index 5ecc48b025..a7a26ef350 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3071,6 +3071,7 @@ union specbinding
       ENUM_BF (specbind_tag) kind : CHAR_BIT;
       void (*func) (Lisp_Object);
       Lisp_Object arg;
+      EMACS_INT eval_depth;
     } unwind;
     struct {
       ENUM_BF (specbind_tag) kind : CHAR_BIT;
-- 
2.17.1