all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Dmitry Antipov <dmantipov@yandex.ru>
To: Emacs development discussions <emacs-devel@gnu.org>
Subject: eval proposals
Date: Fri, 06 Jun 2014 19:33:41 +0400	[thread overview]
Message-ID: <5391DF55.5090608@yandex.ru> (raw)

[-- Attachment #1: Type: text/plain, Size: 918 bytes --]

I would like to propose and discuss two small features below:

1) Protection against C stack overflow caused by enormously huge
    `max-lisp-eval-depth'.  Note that the stack size limit is examined
    just once (because doing it each time when eval_sub or funcall is
    called introduces too much overhead), but some OSes are capable to
    change this limit when the program is running (prlimit on Linux,
    for example).

2) Capability to shrink specpdl stack if it becomes too large.  When
    `max-specpdl-size' is 83200000 and `max-lisp-eval-depth' is 640000,
    this extreme example with 10K let bindings:

    (defun f ()
      (let ((x0 0)
            (x1 1)
            ...
            (x9999 9999)) (f)))

    creates 73622255-slots specpdl stack before running out of C stack
    on my system, which results in 2.5G RSS.  And currently there is no
    way to reduce it back to reasonable size.

Dmitry

[-- Attachment #2: eval.patch --]
[-- Type: text/x-patch, Size: 3527 bytes --]

=== modified file 'src/alloc.c'
--- src/alloc.c	2014-06-02 00:18:22 +0000
+++ src/alloc.c	2014-06-06 15:14:47 +0000
@@ -5600,6 +5600,7 @@
   block_input ();
 
   shrink_regexp_cache ();
+  shrink_specpdl ();
 
   gc_in_progress = 1;
 

=== modified file 'src/eval.c'
--- src/eval.c	2014-02-10 09:48:17 +0000
+++ src/eval.c	2014-06-06 15:14:15 +0000
@@ -33,6 +33,10 @@
 #include "xterm.h"
 #endif
 
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
 /* Chain of condition and catch handlers currently in effect.  */
 
 struct handler *handlerlist;
@@ -240,6 +244,34 @@
 
 static struct handler handlerlist_sentinel;
 
+/* C stack overflow protection.  This should protect from SIGSEGV when
+   `max-lisp-eval-depth' is too large.  Note that it doesn't protect
+   from other kinds of overflows, e.g. too deep recursion in mark_object. */
+
+#if defined (HAVE_GETRLIMIT) && defined (RLIMIT_STACK)
+
+/* Extra stack space to reserve.  */
+#define STACK_EXTRA (64 * 1024)
+
+/* Current C stack slimit.  */
+static struct rlimit stack_limit;
+
+#define STACK_GUARD() do {					\
+    ptrdiff_t stack_size;					\
+    if ((char *) &stack_size < stack_bottom)			\
+      stack_size = stack_bottom - (char *) &stack_size;	\
+    else							\
+      stack_size = (char *) &stack_size - stack_bottom;	\
+    if (stack_size + STACK_EXTRA > stack_limit.rlim_cur)	\
+      error ("Attempt to overflow C stack");			\
+  } while (0)
+
+#else /* !HAVE_GETRLIMIT || !RLIMIT_STACK */
+
+#define STACK_GUARD() ((void) 0)
+
+#endif /* HAVE_GETRLIMIT && RLIMIT_STACK */
+
 void
 init_eval (void)
 {
@@ -262,6 +294,10 @@
 #endif
   /* This is less than the initial value of num_nonmacro_input_events.  */
   when_entered_debugger = -1;
+#if defined (HAVE_GETRLIMIT) && defined (RLIMIT_STACK)
+  if (getrlimit (RLIMIT_STACK, &stack_limit))
+    emacs_abort ();
+#endif /* HAVE_GETRLIMIT && RLIMIT_STACK */
 }
 
 /* Unwind-protect function used by call_debugger.  */
@@ -2039,6 +2075,28 @@
     }
 }
 
+/* If the specpdl stack is larger than number of currently used
+   slots multiplied by SPECPDL_SHRINK_FACTOR, shrink it to this
+   size.  Called by GC.  */
+
+void
+shrink_specpdl (void)
+{
+  enum { SPECPDL_SHRINK_FACTOR = 50 };
+  ptrdiff_t newsize = (specpdl_ptr - specpdl) * SPECPDL_SHRINK_FACTOR;
+
+  if (newsize < specpdl_size)
+    {
+      ptrdiff_t count = SPECPDL_INDEX ();
+      union specbinding *pdlvec = specpdl - 1;
+
+      pdlvec = xrealloc (pdlvec, (newsize + 1) * sizeof *specpdl);
+      specpdl = pdlvec + 1;
+      specpdl_size = newsize;
+      specpdl_ptr = specpdl + count;
+    }
+}
+
 void
 record_in_backtrace (Lisp_Object function, Lisp_Object *args, ptrdiff_t nargs)
 {
@@ -2060,6 +2118,8 @@
   Lisp_Object funcar;
   struct gcpro gcpro1, gcpro2, gcpro3;
 
+  STACK_GUARD ();
+
   if (SYMBOLP (form))
     {
       /* Look up its binding in the lexical environment.
@@ -2749,6 +2809,8 @@
   register Lisp_Object *internal_args;
   ptrdiff_t i;
 
+  STACK_GUARD ();
+
   QUIT;
 
   if (++lisp_eval_depth > max_lisp_eval_depth)

=== modified file 'src/lisp.h'
--- src/lisp.h	2014-06-02 06:08:49 +0000
+++ src/lisp.h	2014-06-06 15:13:23 +0000
@@ -3907,6 +3907,7 @@
 extern _Noreturn void xsignal3 (Lisp_Object, Lisp_Object, Lisp_Object,
 				Lisp_Object);
 extern _Noreturn void signal_error (const char *, Lisp_Object);
+extern void shrink_specpdl (void);
 extern Lisp_Object eval_sub (Lisp_Object form);
 extern Lisp_Object apply1 (Lisp_Object, Lisp_Object);
 extern Lisp_Object call0 (Lisp_Object);


             reply	other threads:[~2014-06-06 15:33 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-06-06 15:33 Dmitry Antipov [this message]
2014-06-06 16:17 ` eval proposals Paul Eggert
2014-06-06 16:59   ` Eli Zaretskii
2014-06-06 17:14   ` Stefan Monnier
2014-06-06 16:58 ` Stefan Monnier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5391DF55.5090608@yandex.ru \
    --to=dmantipov@yandex.ru \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.