diff options
| author | Paul Eggert | 2013-07-12 17:24:38 -0700 |
|---|---|---|
| committer | Paul Eggert | 2013-07-12 17:24:38 -0700 |
| commit | 5e301d7651c0691bb2bc7f3fbe711fdbe26ac471 (patch) | |
| tree | ee4962eb5ebb86a5de385d554b854864b9a53f21 /src/eval.c | |
| parent | c04bbd85c9b5a7db4b7fb62e741563aa848dce67 (diff) | |
| download | emacs-5e301d7651c0691bb2bc7f3fbe711fdbe26ac471.tar.gz emacs-5e301d7651c0691bb2bc7f3fbe711fdbe26ac471.zip | |
Don't lose top specpdl entry when memory is exhausted.
* eval.c (grow_specpdl): Increment specpdl top by 1 and check for
specpdl overflow here, to simplify callers; all callers changed.
Always reserve an unused entry at the stack top; this avoids
losing the top entry's information when memory is exhausted.
Diffstat (limited to 'src/eval.c')
| -rw-r--r-- | src/eval.c | 56 |
1 files changed, 33 insertions, 23 deletions
diff --git a/src/eval.c b/src/eval.c index 31a774b9d27..0e231bdb285 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -1996,38 +1996,52 @@ If LEXICAL is t, evaluate using lexical scoping. */) | |||
| 1996 | return unbind_to (count, eval_sub (form)); | 1996 | return unbind_to (count, eval_sub (form)); |
| 1997 | } | 1997 | } |
| 1998 | 1998 | ||
| 1999 | /* Grow the specpdl stack by one entry. | ||
| 2000 | The caller should have already initialized the entry. | ||
| 2001 | Signal an error on stack overflow. | ||
| 2002 | |||
| 2003 | Make sure that there is always one unused entry past the top of the | ||
| 2004 | stack, so that the just-initialized entry is safely unwound if | ||
| 2005 | memory exhausted and an error is signaled here. Also, allocate a | ||
| 2006 | never-used entry just before the bottom of the stack; sometimes its | ||
| 2007 | address is taken. */ | ||
| 2008 | |||
| 1999 | static void | 2009 | static void |
| 2000 | grow_specpdl (void) | 2010 | grow_specpdl (void) |
| 2001 | { | 2011 | { |
| 2002 | ptrdiff_t count = SPECPDL_INDEX (); | 2012 | specpdl_ptr++; |
| 2003 | ptrdiff_t max_size = min (max_specpdl_size, PTRDIFF_MAX - 1000); | 2013 | |
| 2004 | union specbinding *pdlvec = specpdl - 1; | 2014 | if (specpdl_ptr == specpdl + specpdl_size) |
| 2005 | ptrdiff_t pdlvecsize = specpdl_size + 1; | ||
| 2006 | if (max_size <= specpdl_size) | ||
| 2007 | { | 2015 | { |
| 2008 | if (max_specpdl_size < 400) | 2016 | ptrdiff_t count = SPECPDL_INDEX (); |
| 2009 | max_size = max_specpdl_size = 400; | 2017 | ptrdiff_t max_size = min (max_specpdl_size, PTRDIFF_MAX - 1000); |
| 2018 | union specbinding *pdlvec = specpdl - 1; | ||
| 2019 | ptrdiff_t pdlvecsize = specpdl_size + 1; | ||
| 2010 | if (max_size <= specpdl_size) | 2020 | if (max_size <= specpdl_size) |
| 2011 | signal_error ("Variable binding depth exceeds max-specpdl-size", Qnil); | 2021 | { |
| 2022 | if (max_specpdl_size < 400) | ||
| 2023 | max_size = max_specpdl_size = 400; | ||
| 2024 | if (max_size <= specpdl_size) | ||
| 2025 | signal_error ("Variable binding depth exceeds max-specpdl-size", | ||
| 2026 | Qnil); | ||
| 2027 | } | ||
| 2028 | pdlvec = xpalloc (pdlvec, &pdlvecsize, 1, max_size + 1, sizeof *specpdl); | ||
| 2029 | specpdl = pdlvec + 1; | ||
| 2030 | specpdl_size = pdlvecsize - 1; | ||
| 2031 | specpdl_ptr = specpdl + count; | ||
| 2012 | } | 2032 | } |
| 2013 | pdlvec = xpalloc (pdlvec, &pdlvecsize, 1, max_size + 1, sizeof *specpdl); | ||
| 2014 | specpdl = pdlvec + 1; | ||
| 2015 | specpdl_size = pdlvecsize - 1; | ||
| 2016 | specpdl_ptr = specpdl + count; | ||
| 2017 | } | 2033 | } |
| 2018 | 2034 | ||
| 2019 | void | 2035 | void |
| 2020 | record_in_backtrace (Lisp_Object function, Lisp_Object *args, ptrdiff_t nargs) | 2036 | record_in_backtrace (Lisp_Object function, Lisp_Object *args, ptrdiff_t nargs) |
| 2021 | { | 2037 | { |
| 2022 | eassert (nargs >= UNEVALLED); | 2038 | eassert (nargs >= UNEVALLED); |
| 2023 | if (specpdl_ptr == specpdl + specpdl_size) | ||
| 2024 | grow_specpdl (); | ||
| 2025 | specpdl_ptr->bt.kind = SPECPDL_BACKTRACE; | 2039 | specpdl_ptr->bt.kind = SPECPDL_BACKTRACE; |
| 2026 | specpdl_ptr->bt.debug_on_exit = false; | 2040 | specpdl_ptr->bt.debug_on_exit = false; |
| 2027 | specpdl_ptr->bt.function = function; | 2041 | specpdl_ptr->bt.function = function; |
| 2028 | specpdl_ptr->bt.args = args; | 2042 | specpdl_ptr->bt.args = args; |
| 2029 | specpdl_ptr->bt.nargs = nargs; | 2043 | specpdl_ptr->bt.nargs = nargs; |
| 2030 | specpdl_ptr++; | 2044 | grow_specpdl (); |
| 2031 | } | 2045 | } |
| 2032 | 2046 | ||
| 2033 | /* Eval a sub-expression of the current expression (i.e. in the same | 2047 | /* Eval a sub-expression of the current expression (i.e. in the same |
| @@ -3113,8 +3127,6 @@ specbind (Lisp_Object symbol, Lisp_Object value) | |||
| 3113 | 3127 | ||
| 3114 | CHECK_SYMBOL (symbol); | 3128 | CHECK_SYMBOL (symbol); |
| 3115 | sym = XSYMBOL (symbol); | 3129 | sym = XSYMBOL (symbol); |
| 3116 | if (specpdl_ptr == specpdl + specpdl_size) | ||
| 3117 | grow_specpdl (); | ||
| 3118 | 3130 | ||
| 3119 | start: | 3131 | start: |
| 3120 | switch (sym->redirect) | 3132 | switch (sym->redirect) |
| @@ -3127,7 +3139,7 @@ specbind (Lisp_Object symbol, Lisp_Object value) | |||
| 3127 | specpdl_ptr->let.kind = SPECPDL_LET; | 3139 | specpdl_ptr->let.kind = SPECPDL_LET; |
| 3128 | specpdl_ptr->let.symbol = symbol; | 3140 | specpdl_ptr->let.symbol = symbol; |
| 3129 | specpdl_ptr->let.old_value = SYMBOL_VAL (sym); | 3141 | specpdl_ptr->let.old_value = SYMBOL_VAL (sym); |
| 3130 | ++specpdl_ptr; | 3142 | grow_specpdl (); |
| 3131 | if (!sym->constant) | 3143 | if (!sym->constant) |
| 3132 | SET_SYMBOL_VAL (sym, value); | 3144 | SET_SYMBOL_VAL (sym, value); |
| 3133 | else | 3145 | else |
| @@ -3162,7 +3174,7 @@ specbind (Lisp_Object symbol, Lisp_Object value) | |||
| 3162 | if (NILP (Flocal_variable_p (symbol, Qnil))) | 3174 | if (NILP (Flocal_variable_p (symbol, Qnil))) |
| 3163 | { | 3175 | { |
| 3164 | specpdl_ptr->let.kind = SPECPDL_LET_DEFAULT; | 3176 | specpdl_ptr->let.kind = SPECPDL_LET_DEFAULT; |
| 3165 | ++specpdl_ptr; | 3177 | grow_specpdl (); |
| 3166 | Fset_default (symbol, value); | 3178 | Fset_default (symbol, value); |
| 3167 | return; | 3179 | return; |
| 3168 | } | 3180 | } |
| @@ -3170,7 +3182,7 @@ specbind (Lisp_Object symbol, Lisp_Object value) | |||
| 3170 | else | 3182 | else |
| 3171 | specpdl_ptr->let.kind = SPECPDL_LET; | 3183 | specpdl_ptr->let.kind = SPECPDL_LET; |
| 3172 | 3184 | ||
| 3173 | specpdl_ptr++; | 3185 | grow_specpdl (); |
| 3174 | set_internal (symbol, value, Qnil, 1); | 3186 | set_internal (symbol, value, Qnil, 1); |
| 3175 | break; | 3187 | break; |
| 3176 | } | 3188 | } |
| @@ -3181,12 +3193,10 @@ specbind (Lisp_Object symbol, Lisp_Object value) | |||
| 3181 | void | 3193 | void |
| 3182 | record_unwind_protect (Lisp_Object (*function) (Lisp_Object), Lisp_Object arg) | 3194 | record_unwind_protect (Lisp_Object (*function) (Lisp_Object), Lisp_Object arg) |
| 3183 | { | 3195 | { |
| 3184 | if (specpdl_ptr == specpdl + specpdl_size) | ||
| 3185 | grow_specpdl (); | ||
| 3186 | specpdl_ptr->unwind.kind = SPECPDL_UNWIND; | 3196 | specpdl_ptr->unwind.kind = SPECPDL_UNWIND; |
| 3187 | specpdl_ptr->unwind.func = function; | 3197 | specpdl_ptr->unwind.func = function; |
| 3188 | specpdl_ptr->unwind.arg = arg; | 3198 | specpdl_ptr->unwind.arg = arg; |
| 3189 | specpdl_ptr++; | 3199 | grow_specpdl (); |
| 3190 | } | 3200 | } |
| 3191 | 3201 | ||
| 3192 | Lisp_Object | 3202 | Lisp_Object |