diff options
| author | Paul Eggert | 2017-07-14 04:54:05 -0700 |
|---|---|---|
| committer | Paul Eggert | 2017-07-14 04:57:18 -0700 |
| commit | 9dee1c884eb50ba282eb9dd2495c5269add25963 (patch) | |
| tree | 947b4c3c21e4bef82795cfbd60f29e371b0e2cc3 /src | |
| parent | 6443a95ad74d54b8be5ba85af9b893f3f1d5fa02 (diff) | |
| download | emacs-9dee1c884eb50ba282eb9dd2495c5269add25963.tar.gz emacs-9dee1c884eb50ba282eb9dd2495c5269add25963.zip | |
Improve stack-overflow heuristic on GNU/Linux
Problem reported by Steve Kemp (Bug#27585).
* src/eval.c (near_C_stack_top): Remove. All uses replaced
by current_thread->stack_top.
(record_in_backtrace): Set current_thread->stack_top.
This is for when the Lisp interpreter calls itself.
* src/lread.c (read1): Set current_thread->stack_top.
This is for recursive s-expression reads.
* src/print.c (print_object): Set current_thread->stack_top.
This is for recursive s-expression printing.
* src/thread.c (mark_one_thread): Get stack top first.
* src/thread.h (struct thread_state.stack_top): Now void *, not char *.
Diffstat (limited to 'src')
| -rw-r--r-- | src/eval.c | 9 | ||||
| -rw-r--r-- | src/lisp.h | 1 | ||||
| -rw-r--r-- | src/lread.c | 1 | ||||
| -rw-r--r-- | src/print.c | 2 | ||||
| -rw-r--r-- | src/sysdep.c | 2 | ||||
| -rw-r--r-- | src/thread.c | 10 | ||||
| -rw-r--r-- | src/thread.h | 10 |
7 files changed, 18 insertions, 17 deletions
diff --git a/src/eval.c b/src/eval.c index 8f293c9d300..e5900382dee 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -213,13 +213,6 @@ backtrace_next (union specbinding *pdl) | |||
| 213 | return pdl; | 213 | return pdl; |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | /* Return a pointer to somewhere near the top of the C stack. */ | ||
| 217 | void * | ||
| 218 | near_C_stack_top (void) | ||
| 219 | { | ||
| 220 | return backtrace_args (backtrace_top ()); | ||
| 221 | } | ||
| 222 | |||
| 223 | void | 216 | void |
| 224 | init_eval_once (void) | 217 | init_eval_once (void) |
| 225 | { | 218 | { |
| @@ -2090,7 +2083,7 @@ record_in_backtrace (Lisp_Object function, Lisp_Object *args, ptrdiff_t nargs) | |||
| 2090 | specpdl_ptr->bt.kind = SPECPDL_BACKTRACE; | 2083 | specpdl_ptr->bt.kind = SPECPDL_BACKTRACE; |
| 2091 | specpdl_ptr->bt.debug_on_exit = false; | 2084 | specpdl_ptr->bt.debug_on_exit = false; |
| 2092 | specpdl_ptr->bt.function = function; | 2085 | specpdl_ptr->bt.function = function; |
| 2093 | specpdl_ptr->bt.args = args; | 2086 | current_thread->stack_top = specpdl_ptr->bt.args = args; |
| 2094 | specpdl_ptr->bt.nargs = nargs; | 2087 | specpdl_ptr->bt.nargs = nargs; |
| 2095 | grow_specpdl (); | 2088 | grow_specpdl (); |
| 2096 | 2089 | ||
diff --git a/src/lisp.h b/src/lisp.h index f5cb6c75706..1e8ef7a449a 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3874,7 +3874,6 @@ extern Lisp_Object vformat_string (const char *, va_list) | |||
| 3874 | ATTRIBUTE_FORMAT_PRINTF (1, 0); | 3874 | ATTRIBUTE_FORMAT_PRINTF (1, 0); |
| 3875 | extern void un_autoload (Lisp_Object); | 3875 | extern void un_autoload (Lisp_Object); |
| 3876 | extern Lisp_Object call_debugger (Lisp_Object arg); | 3876 | extern Lisp_Object call_debugger (Lisp_Object arg); |
| 3877 | extern void *near_C_stack_top (void); | ||
| 3878 | extern void init_eval_once (void); | 3877 | extern void init_eval_once (void); |
| 3879 | extern Lisp_Object safe_call (ptrdiff_t, Lisp_Object, ...); | 3878 | extern Lisp_Object safe_call (ptrdiff_t, Lisp_Object, ...); |
| 3880 | extern Lisp_Object safe_call1 (Lisp_Object, Lisp_Object); | 3879 | extern Lisp_Object safe_call1 (Lisp_Object, Lisp_Object); |
diff --git a/src/lread.c b/src/lread.c index fe5de382677..901e40b3489 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -2676,6 +2676,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 2676 | bool uninterned_symbol = false; | 2676 | bool uninterned_symbol = false; |
| 2677 | bool multibyte; | 2677 | bool multibyte; |
| 2678 | char stackbuf[MAX_ALLOCA]; | 2678 | char stackbuf[MAX_ALLOCA]; |
| 2679 | current_thread->stack_top = stackbuf; | ||
| 2679 | 2680 | ||
| 2680 | *pch = 0; | 2681 | *pch = 0; |
| 2681 | 2682 | ||
diff --git a/src/print.c b/src/print.c index b6ea3ff62a5..12edf015892 100644 --- a/src/print.c +++ b/src/print.c | |||
| @@ -1748,7 +1748,7 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag) | |||
| 1748 | char buf[max (sizeof "from..to..in " + 2 * INT_STRLEN_BOUND (EMACS_INT), | 1748 | char buf[max (sizeof "from..to..in " + 2 * INT_STRLEN_BOUND (EMACS_INT), |
| 1749 | max (sizeof " . #" + INT_STRLEN_BOUND (printmax_t), | 1749 | max (sizeof " . #" + INT_STRLEN_BOUND (printmax_t), |
| 1750 | 40))]; | 1750 | 40))]; |
| 1751 | 1751 | current_thread->stack_top = buf; | |
| 1752 | maybe_quit (); | 1752 | maybe_quit (); |
| 1753 | 1753 | ||
| 1754 | /* Detect circularities and truncate them. */ | 1754 | /* Detect circularities and truncate them. */ |
diff --git a/src/sysdep.c b/src/sysdep.c index b52236769e0..db99f53299c 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -1772,7 +1772,7 @@ stack_overflow (siginfo_t *siginfo) | |||
| 1772 | /* The known top and bottom of the stack. The actual stack may | 1772 | /* The known top and bottom of the stack. The actual stack may |
| 1773 | extend a bit beyond these boundaries. */ | 1773 | extend a bit beyond these boundaries. */ |
| 1774 | char *bot = stack_bottom; | 1774 | char *bot = stack_bottom; |
| 1775 | char *top = near_C_stack_top (); | 1775 | char *top = current_thread->stack_top; |
| 1776 | 1776 | ||
| 1777 | /* Log base 2 of the stack heuristic ratio. This ratio is the size | 1777 | /* Log base 2 of the stack heuristic ratio. This ratio is the size |
| 1778 | of the known stack divided by the size of the guard area past the | 1778 | of the known stack divided by the size of the guard area past the |
diff --git a/src/thread.c b/src/thread.c index e3787971a53..1f7ced386d3 100644 --- a/src/thread.c +++ b/src/thread.c | |||
| @@ -595,14 +595,15 @@ thread_select (select_func *func, int max_fds, fd_set *rfds, | |||
| 595 | static void | 595 | static void |
| 596 | mark_one_thread (struct thread_state *thread) | 596 | mark_one_thread (struct thread_state *thread) |
| 597 | { | 597 | { |
| 598 | struct handler *handler; | 598 | /* Get the stack top now, in case mark_specpdl changes it. */ |
| 599 | Lisp_Object tem; | 599 | void *stack_top = thread->stack_top; |
| 600 | 600 | ||
| 601 | mark_specpdl (thread->m_specpdl, thread->m_specpdl_ptr); | 601 | mark_specpdl (thread->m_specpdl, thread->m_specpdl_ptr); |
| 602 | 602 | ||
| 603 | mark_stack (thread->m_stack_bottom, thread->stack_top); | 603 | mark_stack (thread->m_stack_bottom, stack_top); |
| 604 | 604 | ||
| 605 | for (handler = thread->m_handlerlist; handler; handler = handler->next) | 605 | for (struct handler *handler = thread->m_handlerlist; |
| 606 | handler; handler = handler->next) | ||
| 606 | { | 607 | { |
| 607 | mark_object (handler->tag_or_ch); | 608 | mark_object (handler->tag_or_ch); |
| 608 | mark_object (handler->val); | 609 | mark_object (handler->val); |
| @@ -610,6 +611,7 @@ mark_one_thread (struct thread_state *thread) | |||
| 610 | 611 | ||
| 611 | if (thread->m_current_buffer) | 612 | if (thread->m_current_buffer) |
| 612 | { | 613 | { |
| 614 | Lisp_Object tem; | ||
| 613 | XSETBUFFER (tem, thread->m_current_buffer); | 615 | XSETBUFFER (tem, thread->m_current_buffer); |
| 614 | mark_object (tem); | 616 | mark_object (tem); |
| 615 | } | 617 | } |
diff --git a/src/thread.h b/src/thread.h index 9e94de5c175..52b16f1ba83 100644 --- a/src/thread.h +++ b/src/thread.h | |||
| @@ -62,8 +62,14 @@ struct thread_state | |||
| 62 | char *m_stack_bottom; | 62 | char *m_stack_bottom; |
| 63 | #define stack_bottom (current_thread->m_stack_bottom) | 63 | #define stack_bottom (current_thread->m_stack_bottom) |
| 64 | 64 | ||
| 65 | /* An address near the top of the stack. */ | 65 | /* The address of an object near the C stack top, used to determine |
| 66 | char *stack_top; | 66 | which words need to be scanned by the garbage collector. This is |
| 67 | also used to detect heuristically whether segmentation violation | ||
| 68 | address indicates stack overflow, as opposed to some internal | ||
| 69 | error in Emacs. If the C function F calls G which calls H which | ||
| 70 | calls ... F, then at least one of the functions in the chain | ||
| 71 | should set this to the address of a local variable. */ | ||
| 72 | void *stack_top; | ||
| 67 | 73 | ||
| 68 | struct catchtag *m_catchlist; | 74 | struct catchtag *m_catchlist; |
| 69 | #define catchlist (current_thread->m_catchlist) | 75 | #define catchlist (current_thread->m_catchlist) |