+2014-09-25 Paul Eggert <eggert@cs.ucla.edu>
+
+ Fix local_cons etc. to not exhaust the stack when in a loop.
+ Problem reported in:
+ http://lists.gnu.org/archive/html/emacs-devel/2014-09/msg00696.html
+ * buffer.c (Fother_buffer, other_buffer_safely, init_buffer):
+ * charset.c (load_charset_map_from_file, Ffind_charset_region)
+ (Ffind_charset_string):
+ * chartab.c (uniprop_encode_value_numeric, uniprop_table):
+ * data.c (wrong_range):
+ * editfns.c (Fpropertize, format2):
+ * emacs.c (init_cmdargs, decode_env_path):
+ * fileio.c (auto_save_error):
+ * fns.c (Fyes_or_no_p):
+ * font.c (font_style_to_value, font_parse_xlfd)
+ (font_parse_family_registry, font_delete_unmatched)
+ (font_add_log):
+ * fontset.c (Fset_fontset_font):
+ * frame.c (x_get_arg):
+ * keyboard.c (echo_dash, safe_run_hooks_error, parse_menu_item)
+ (read_char_minibuf_menu_prompt):
+ * keymap.c (silly_event_symbol_error, describe_vector):
+ * lread.c (load_warn_old_style_backquotes):
+ * menu.c (single_menu_item):
+ * minibuf.c (Fread_buffer):
+ * process.c (status_message, Fformat_network_address)
+ (server_accept_connection):
+ * textprop.c (copy_text_properties):
+ * xdisp.c (Fcurrent_bidi_paragraph_direction):
+ * xfns.c (x_default_scroll_bar_color_parameter):
+ * xfont.c (xfont_open):
+ * xselect.c (x_clipboard_manager_error_1):
+ * xterm.c (x_term_init):
+ Put USE_LOCAL_ALLOCA at the start of the function.
+ * fns.c (maybe_resize_hash_table): Use build_string instead of
+ build_local_string, since we'd otherwise need a conditional
+ USE_LOCAL_ALLOCA here, but this is just debugging output and is
+ not worth the bother of optimization.
+ * font.c (font_delete_unmatched): Remove by-hand code that
+ observed MAX_ALLOCA limit, since it's now done automatically.
+ * keymap.c (Fsingle_key_description): Put USE_SAFE_ALLOCA at top,
+ since build_local_string needs its sa_alloc.
+ * lisp.h (lisp_word_count): New function.
+ (SAFE_ALLOCA_LISP): Use it.
+ (USE_LOCAL_ALLOCA): New macro.
+ (local_cons, make_local_vector, make_local_string):
+ Observe the MAX_ALLOCA limit.
+ (LISP_STRING_OVERHEAD): New constant.
+ (make_local_string): Use it.
+
2014-09-24 Paul Eggert <eggert@cs.ucla.edu>
Default to stack objects on non-GNU/Linux, non-DOS_NT platforms.
The buffer is found by scanning the selected or specified frame's buffer
list first, followed by the list of all buffers. If no other buffer
exists, return the buffer `*scratch*' (creating it if necessary). */)
- (register Lisp_Object buffer, Lisp_Object visible_ok, Lisp_Object frame)
+ (Lisp_Object buffer, Lisp_Object visible_ok, Lisp_Object frame)
{
+ USE_LOCAL_ALLOCA;
struct frame *f = decode_any_frame (frame);
Lisp_Object tail = f->buffer_list, pred = f->buffer_predicate;
Lisp_Object buf, notsogood = Qnil;
Lisp_Object
other_buffer_safely (Lisp_Object buffer)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object tail, buf;
FOR_EACH_LIVE_BUFFER (tail, buf)
void
init_buffer (int initialized)
{
+ USE_LOCAL_ALLOCA;
char *pwd;
Lisp_Object temp;
ptrdiff_t len;
load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile,
int control_flag)
{
+ USE_LOCAL_ALLOCA;
unsigned min_code = CHARSET_MIN_CODE (charset);
unsigned max_code = CHARSET_MAX_CODE (charset);
int fd;
only `ascii', `eight-bit-control', and `eight-bit-graphic'. */)
(Lisp_Object beg, Lisp_Object end, Lisp_Object table)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object charsets;
ptrdiff_t from, from_byte, to, stop, stop_byte;
int i;
only `ascii', `eight-bit-control', and `eight-bit-graphic'. */)
(Lisp_Object str, Lisp_Object table)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object charsets;
int i;
Lisp_Object val;
static Lisp_Object
uniprop_encode_value_numeric (Lisp_Object table, Lisp_Object value)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object *value_table = XVECTOR (XCHAR_TABLE (table)->extras[4])->contents;
int i, size = ASIZE (XCHAR_TABLE (table)->extras[4]);
Lisp_Object
uniprop_table (Lisp_Object prop)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object val, table, result;
val = Fassq (prop, Vchar_code_property_alist);
static void
wrong_range (Lisp_Object min, Lisp_Object max, Lisp_Object wrong)
{
+ USE_LOCAL_ALLOCA;
xsignal2 (Qerror, Fconcat (4, ((Lisp_Object [])
{ build_local_string ("Value should be from "),
Fnumber_to_string (min),
usage: (propertize STRING &rest PROPERTIES) */)
(ptrdiff_t nargs, Lisp_Object *args)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object properties, string;
struct gcpro gcpro1, gcpro2;
ptrdiff_t i;
Lisp_Object
format2 (const char *string1, Lisp_Object arg0, Lisp_Object arg1)
{
+ USE_LOCAL_ALLOCA;
return Fformat (3, ((Lisp_Object [])
{ build_local_string (string1), arg0, arg1 }));
}
static void
init_cmdargs (int argc, char **argv, int skip_args, char *original_pwd)
{
- register int i;
+ USE_LOCAL_ALLOCA;
+ int i;
Lisp_Object name, dir, handler;
ptrdiff_t count = SPECPDL_INDEX ();
Lisp_Object raw_name;
Lisp_Object
decode_env_path (const char *evarname, const char *defalt, bool empty)
{
+ USE_LOCAL_ALLOCA;
const char *path, *p;
Lisp_Object lpath, element, tem;
/* Default is to use "." for empty path elements.
static Lisp_Object
auto_save_error (Lisp_Object error_val)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object msg;
int i;
struct gcpro gcpro1;
if `last-nonmenu-event' is nil, and `use-dialog-box' is non-nil. */)
(Lisp_Object prompt)
{
- register Lisp_Object ans;
+ USE_LOCAL_ALLOCA;
+ Lisp_Object ans;
struct gcpro gcpro1;
CHECK_STRING (prompt);
if (HASH_TABLE_P (Vpurify_flag)
&& XHASH_TABLE (Vpurify_flag) == h)
Fmessage (2, ((Lisp_Object [])
- { build_local_string ("Growing hash table to: %d"),
+ { build_string ("Growing hash table to: %d"),
make_number (new_size) }));
#endif
font_style_to_value (enum font_property_index prop, Lisp_Object val,
bool noerror)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object table = AREF (font_style_table, prop - FONT_WEIGHT_INDEX);
int len;
int
font_parse_xlfd (char *name, ptrdiff_t len, Lisp_Object font)
{
+ USE_LOCAL_ALLOCA;
int i, j, n;
char *f[XLFD_LAST_INDEX + 1];
Lisp_Object val;
void
font_parse_family_registry (Lisp_Object family, Lisp_Object registry, Lisp_Object font_spec)
{
+ USE_LOCAL_ALLOCA;
ptrdiff_t len;
char *p0, *p1;
static Lisp_Object
font_delete_unmatched (Lisp_Object vec, Lisp_Object spec, int size)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object entity, val;
enum font_property_index prop;
- /* If USE_STACK_LISP_OBJECTS, MAX is used to avoid unbounded alloca. */
- ptrdiff_t i, max
- = (USE_STACK_LISP_OBJECTS ? MAX_ALLOCA / sizeof (struct Lisp_Cons) : 0);
+ ptrdiff_t i;
for (val = Qnil, i = ASIZE (vec) - 1; i >= 0; i--)
{
}
if (NILP (spec))
{
- val = --max > 0 ? local_cons (entity, val) : Fcons (entity, val);
+ val = local_cons (entity, val);
continue;
}
for (prop = FONT_WEIGHT_INDEX; prop < FONT_SIZE_INDEX; prop++)
AREF (entity, FONT_AVGWIDTH_INDEX)))
prop = FONT_SPEC_MAX;
if (prop < FONT_SPEC_MAX)
- val = --max > 0 ? local_cons (entity, val) : Fcons (entity, val);
+ val = local_cons (entity, val);
}
return (Fvconcat (1, &val));
}
void
font_add_log (const char *action, Lisp_Object arg, Lisp_Object result)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object val;
int i;
appended. By default, FONT-SPEC overrides the previous settings. */)
(Lisp_Object name, Lisp_Object target, Lisp_Object font_spec, Lisp_Object frame, Lisp_Object add)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object fontset;
Lisp_Object font_def, registry, family;
Lisp_Object range_list;
x_get_arg (Display_Info *dpyinfo, Lisp_Object alist, Lisp_Object param,
const char *attribute, const char *class, enum resource_types type)
{
- register Lisp_Object tem;
+ USE_LOCAL_ALLOCA;
+ Lisp_Object tem;
tem = Fassq (param, alist);
static void
echo_dash (void)
{
+ USE_LOCAL_ALLOCA;
+
/* Do nothing if not echoing at all. */
if (NILP (KVAR (current_kboard, echo_string)))
return;
static Lisp_Object
safe_run_hooks_error (Lisp_Object error, ptrdiff_t nargs, Lisp_Object *args)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object hook, fun;
eassert (nargs == 2);
bool
parse_menu_item (Lisp_Object item, int inmenubar)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object def, tem, item_string, start;
Lisp_Object filter;
Lisp_Object keyhint;
read_char_minibuf_menu_prompt (int commandflag,
Lisp_Object map)
{
- register Lisp_Object name;
+ USE_LOCAL_ALLOCA;
+ Lisp_Object name;
ptrdiff_t nlength;
/* FIXME: Use the minibuffer's frame width. */
ptrdiff_t width = FRAME_COLS (SELECTED_FRAME ()) - 4;
static void
silly_event_symbol_error (Lisp_Object c)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object parsed, base, name, assoc;
int modifiers;
around function keys and event symbols. */)
(Lisp_Object key, Lisp_Object no_angles)
{
+ USE_SAFE_ALLOCA;
+
if (CONSP (key) && lucid_event_type_list_p (key))
key = Fevent_convert_list (key);
if (NILP (no_angles))
{
Lisp_Object result;
- USE_SAFE_ALLOCA;
char *buffer = SAFE_ALLOCA (sizeof "<>"
+ SBYTES (SYMBOL_NAME (key)));
esprintf (buffer, "<%s>", SDATA (SYMBOL_NAME (key)));
bool partial, Lisp_Object shadow, Lisp_Object entire_map,
bool keymap_p, bool mention_shadow)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object definition;
Lisp_Object tem2;
Lisp_Object elt_prefix = Qnil;
} while (false)
+/* Return floor (NBYTES / WORD_SIZE). */
+
+INLINE ptrdiff_t
+lisp_word_count (ptrdiff_t nbytes)
+{
+ if (-1 >> 1 == -1)
+ switch (word_size)
+ {
+ case 2: return nbytes >> 1;
+ case 4: return nbytes >> 2;
+ case 8: return nbytes >> 3;
+ case 16: return nbytes >> 4;
+ }
+ return nbytes / word_size - (nbytes % word_size < 0);
+}
+
/* SAFE_ALLOCA_LISP allocates an array of Lisp_Objects. */
#define SAFE_ALLOCA_LISP(buf, nelt) \
do { \
- if ((nelt) <= sa_avail / word_size) \
+ if ((nelt) <= lisp_word_count (sa_avail)) \
(buf) = AVAIL_ALLOCA ((nelt) * word_size); \
else if ((nelt) <= min (PTRDIFF_MAX, SIZE_MAX) / word_size) \
{ \
# define USE_LOCAL_ALLOCATORS
#endif
+/* Any function that uses a local allocator should start with either
+ 'USE_SAFE_ALLOCA; or 'USE_LOCAL_ALLOCA;' (but not both). */
+#ifdef USE_LOCAL_ALLOCATORS
+# define USE_LOCAL_ALLOCA ptrdiff_t sa_avail = MAX_ALLOCA
+#else
+# define USE_LOCAL_ALLOCA
+#endif
+
#ifdef USE_LOCAL_ALLOCATORS
/* Return a function-scoped cons whose car is X and cdr is Y. */
# define local_cons(x, y) \
- ({ \
- struct Lisp_Cons *c_ = alloca (sizeof (struct Lisp_Cons)); \
- c_->car = (x); \
- c_->u.cdr = (y); \
- make_lisp_ptr (c_, Lisp_Cons); \
- })
+ (sizeof (struct Lisp_Cons) <= sa_avail \
+ ? ({ \
+ struct Lisp_Cons *c_ = AVAIL_ALLOCA (sizeof (struct Lisp_Cons)); \
+ c_->car = (x); \
+ c_->u.cdr = (y); \
+ make_lisp_ptr (c_, Lisp_Cons); \
+ }) \
+ : Fcons (x, y))
# define local_list1(a) local_cons (a, Qnil)
# define local_list2(a, b) local_cons (a, local_list1 (b))
# define make_local_vector(size, init) \
({ \
ptrdiff_t size_ = size; \
- Lisp_Object init_ = init; \
Lisp_Object vec_; \
- if (size_ <= (MAX_ALLOCA - header_size) / word_size) \
+ if (size_ <= lisp_word_count (sa_avail - header_size)) \
{ \
- void *ptr_ = alloca (size_ * word_size + header_size); \
- vec_ = local_vector_init (ptr_, size_, init_); \
+ void *ptr_ = AVAIL_ALLOCA (size_ * word_size + header_size); \
+ vec_ = local_vector_init (ptr_, size_, init); \
} \
else \
- vec_ = Fmake_vector (make_number (size_), init_); \
+ vec_ = Fmake_vector (make_number (size_), init); \
vec_; \
})
+enum { LISP_STRING_OVERHEAD = sizeof (struct Lisp_String) + 1 };
+
/* Return a function-scoped string with contents DATA and length NBYTES. */
# define make_local_string(data, nbytes) \
({ \
- char const *data_ = data; \
ptrdiff_t nbytes_ = nbytes; \
Lisp_Object string_; \
- if (nbytes_ <= MAX_ALLOCA - sizeof (struct Lisp_String) - 1) \
+ if (nbytes_ <= sa_avail - LISP_STRING_OVERHEAD) \
{ \
- struct Lisp_String *ptr_ \
- = alloca (sizeof (struct Lisp_String) + 1 + nbytes_); \
- string_ = local_string_init (ptr_, data_, nbytes_); \
+ struct Lisp_String *ptr_ = AVAIL_ALLOCA (LISP_STRING_OVERHEAD \
+ + nbytes_); \
+ string_ = local_string_init (ptr_, data, nbytes_); \
} \
else \
- string_ = make_string (data_, nbytes_); \
+ string_ = make_string (data, nbytes_); \
string_; \
})
static void
load_warn_old_style_backquotes (Lisp_Object file)
{
+ USE_LOCAL_ALLOCA;
if (!NILP (Vold_style_backquotes))
Fmessage (2, ((Lisp_Object [])
{ build_local_string ("Loading `%s': old-style backquotes detected!"),
static Lisp_Object
read_list (bool flag, Lisp_Object readcharfun)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object val, tail;
Lisp_Object elt, tem;
struct gcpro gcpro1, gcpro2;
static void
single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *skp_v)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object map, item_string, enabled;
struct gcpro gcpro1, gcpro2;
bool res;
function, instead of the usual behavior. */)
(Lisp_Object prompt, Lisp_Object def, Lisp_Object require_match)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object result;
char *s;
ptrdiff_t len;
static Lisp_Object
status_message (struct Lisp_Process *p)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object status = p->status;
Lisp_Object symbol;
int code;
Returns nil if format of ADDRESS is invalid. */)
(Lisp_Object address, Lisp_Object omit_port)
{
+ USE_LOCAL_ALLOCA;
+
if (NILP (address))
return Qnil;
static void
server_accept_connection (Lisp_Object server, int channel)
{
+ USE_LOCAL_ALLOCA;
Lisp_Object proc, caller, name, buffer;
Lisp_Object contact, host, service;
struct Lisp_Process *ps= XPROCESS (server);
copy_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object src,
Lisp_Object pos, Lisp_Object dest, Lisp_Object prop)
{
+ USE_LOCAL_ALLOCA;
INTERVAL i;
Lisp_Object res;
Lisp_Object stuff;
See also `bidi-paragraph-direction'. */)
(Lisp_Object buffer)
{
+ USE_LOCAL_ALLOCA;
struct buffer *buf = current_buffer;
struct buffer *old = buf;
const char *xprop, const char *xclass,
int foreground_p)
{
+ USE_LOCAL_ALLOCA;
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
Lisp_Object tem;
void
select_visual (struct x_display_info *dpyinfo)
{
+ USE_LOCAL_ALLOCA;
Display *dpy = dpyinfo->display;
Screen *screen = dpyinfo->screen;
static Lisp_Object
xfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
{
+ USE_LOCAL_ALLOCA;
Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
Display *display = dpyinfo->display;
char name[512];
static Lisp_Object
x_clipboard_manager_error_1 (Lisp_Object err)
{
+ USE_LOCAL_ALLOCA;
Fmessage (2, ((Lisp_Object [])
{ build_local_string ("X clipboard manager error: %s\n\
If the problem persists, set `x-select-enable-clipboard-manager' to nil."),
x_clipboard_manager_save_all (void)
{
/* Loop through all X displays, saving owned clipboards. */
+ USE_LOCAL_ALLOCA;
struct x_display_info *dpyinfo;
Lisp_Object local_selection, local_frame;
struct x_display_info *
x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
{
+ USE_LOCAL_ALLOCA;
Display *dpy;
struct terminal *terminal;
struct x_display_info *dpyinfo;