=== 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 +#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);