all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* eval proposals
@ 2014-06-06 15:33 Dmitry Antipov
  2014-06-06 16:17 ` Paul Eggert
  2014-06-06 16:58 ` Stefan Monnier
  0 siblings, 2 replies; 5+ messages in thread
From: Dmitry Antipov @ 2014-06-06 15:33 UTC (permalink / raw)
  To: Emacs development discussions

[-- 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);


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2014-06-06 17:14 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-06-06 15:33 eval proposals Dmitry Antipov
2014-06-06 16:17 ` Paul Eggert
2014-06-06 16:59   ` Eli Zaretskii
2014-06-06 17:14   ` Stefan Monnier
2014-06-06 16:58 ` Stefan Monnier

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.