all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
@ 2014-09-05  6:08 Paul Eggert
  2014-09-05  8:45 ` Dmitry Antipov
                   ` (2 more replies)
  0 siblings, 3 replies; 23+ messages in thread
From: Paul Eggert @ 2014-09-05  6:08 UTC (permalink / raw
  To: 18410

[-- Attachment #1: Type: text/plain, Size: 267 bytes --]

Tags: patch

Attached is a patch to fix the unbounded alloca calls that I found when 
auditing the Emacs source.  I'm sending this to bug-gnu-emacs to give 
Eli a heads-up, as some of the fixes affect Windows code.  This patch is 
relative to Emacs trunk bzr 117822.

[-- Attachment #2: alloca.patch --]
[-- Type: text/plain, Size: 88863 bytes --]

=== modified file 'src/ChangeLog'
--- src/ChangeLog	2014-09-04 05:38:37 +0000
+++ src/ChangeLog	2014-09-05 06:03:28 +0000
@@ -1,3 +1,101 @@
+2014-09-05  Paul Eggert  <eggert@cs.ucla.edu>
+
+	Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
+	This follows up on the recent thread in emacs-devel on alloca; see:
+	http://lists.gnu.org/archive/html/emacs-devel/2014-09/msg00042.html
+	This patch also cleans up alloca-related glitches noted while
+	examining the code looking for unbounded alloca.
+	* alloc.c (listn):
+	* callproc.c (init_callproc):
+	Rewrite to avoid need for alloca.
+	* buffer.c (mouse_face_overlay_overlaps)
+	(report_overlay_modification):
+	* buffer.h (GET_OVERLAYS_AT):
+	* coding.c (make_subsidiaries):
+	* doc.c (Fsnarf_documentation):
+	* editfns.c (Fuser_full_name):
+	* fileio.c (Ffile_name_directory, Fexpand_file_name)
+	(search_embedded_absfilename, Fsubstitute_in_file_name):
+	* fns.c (Fmake_hash_table):
+	* font.c (font_vconcat_entity_vectors, font_update_drivers):
+	* fontset.c (fontset_pattern_regexp, Ffontset_info):
+	* frame.c (Fmake_terminal_frame, x_set_frame_parameters)
+	(xrdb_get_resource, x_get_resource_string):
+	* ftfont.c (ftfont_get_charset, ftfont_check_otf, ftfont_drive_otf):
+	* ftxfont.c (ftxfont_draw):
+	* image.c (xbm_load, xpm_load, jpeg_load_body):
+	* keyboard.c (echo_add_key, menu_bar_items, tool_bar_items):
+	* keymap.c (Fdescribe_buffer_bindings, describe_map):
+	* lread.c (openp):
+	* menu.c (digest_single_submenu, find_and_call_menu_selection)
+	(find_and_return_menu_selection):
+	* print.c (PRINTFINISH):
+	* process.c (Fformat_network_address):
+	* scroll.c (do_scrolling, do_direct_scrolling, scrolling_1):
+	* search.c (search_buffer, Fmatch_data, Fregexp_quote):
+	* sound.c (wav_play, au_play):
+	* syntax.c (skip_chars):
+	* term.c (tty_menu_activate, tty_menu_show):
+	* textprop.c (get_char_property_and_overlay):
+	* window.c (Fset_window_configuration):
+	* xdisp.c (safe__call, next_overlay_change, vmessage)
+	(compute_overhangs_and_x, draw_glyphs, note_mouse_highlight):
+	* xfaces.c (face_at_buffer_position):
+	* xmenu.c (x_menu_show):
+	Use SAFE_ALLOCA etc. instead of plain alloca, since the
+	allocation size isn't bounded.
+	* callint.c (Fcall_interactively): Redo memory_full check
+	so that it can be done at compile-time on some platforms.
+	* coding.c (MAX_LOOKUP_MAX): New constant.
+	(get_translation_table): Use it.
+	* callproc.c (call_process): Use SAFE_NALLOCA instead of
+	SAFE_ALLOCA, to catch integer overflows on size calculation.
+	(exec_failed) [!DOS_NT]: New function.
+	(child_setup) [!DOS_NT]: Use it.
+	* editfns.c (Ftranspose_regions):
+	Hoist USE_SAFE_ALLOC + SAFE_FREE out of 'if'.
+	* editfns.c (check_translation):
+	Allocate larger buffers on the heap.
+	* eval.c (internal_lisp_condition_case):
+	Check for MAX_ALLOCA overflow.
+	* fns.c (sort_vector): Use SAFE_ALLOCA_LISP rather than Fmake_vector.
+	(Fbase64_encode_region, Fbase64_decode_region):
+	Avoid unnecessary calls to SAFE_FREE before 'error'.
+	* buffer.c (mouse_face_overlay_overlaps):
+	* editfns.c (Fget_pos_property, check_translation):
+	* eval.c (Ffuncall):
+	* font.c (font_unparse_xlfd, font_find_for_lface):
+	* ftfont.c (ftfont_drive_otf):
+	* keyboard.c (echo_add_key, read_decoded_event_from_main_queue)
+	(menu_bar_items, tool_bar_items):
+	* sound.c (Fplay_sound_internal):
+	* xdisp.c (load_overlay_strings, dump_glyph_row):
+	Use an ordinary auto buffer rather than alloca, since the
+	allocation size is fixed and small.
+	* ftfont.c: Include <c-strcase.h>.
+	(matching_prefix): New function.
+	(get_adstyle_property): Use it, to avoid need for alloca.
+	* keyboard.c (echo_add_key):
+	* keymap.c (describe_map): Use ptrdiff_t, not int.
+	* keyboard.c (echo_add_key): Prefer sizeof to strlen.
+	* keymap.c (Fdescribe_buffer_bindings): Use SBYTES, not SCHARS,
+	when counting bytes.
+	* lisp.h (xlispstrdupa): Remove, replacing with ...
+	(SAFE_ALLOCA_STRING): ... new macro with different API.
+	This fixes a portability problem, namely, alloca result
+	passed to another function.  All uses changed.
+	(SAFE_ALLOCA, SAFE_ALLOCA_LISP): Check for MAX_ALLOCA,
+	not MAX_ALLOCA - 1.
+	* regex.c (REGEX_USE_SAFE_ALLOCA, REGEX_SAFE_FREE)
+	(REGEX_ALLOCATE): New macros.
+	(REGEX_REALLOCATE, REGEX_ALLOCATE_STACK, REGEX_REALLOCATE_STACK)
+	(REGEX_FREE_STACK, FREE_VARIABLES, re_match_2_internal):
+	Use them.
+	* xdisp.c (message3): Use SAFE_ALLOCA_STRING rather than doing it
+	by hand.
+	(decode_mode_spec_coding): Store directly into buf rather than
+	into an alloca temporary and copying the temporary to the buf.
+
 2014-09-04  Jan D  <jhd@f20.localdomain>
 
 	* xterm.c (x_term_init): Don't call x_session_initialize if running

=== modified file 'src/alloc.c'
--- src/alloc.c	2014-08-29 07:29:47 +0000
+++ src/alloc.c	2014-09-05 06:03:28 +0000
@@ -2618,29 +2618,28 @@
 Lisp_Object
 listn (enum constype type, ptrdiff_t count, Lisp_Object arg, ...)
 {
+  Lisp_Object (*cons) (Lisp_Object, Lisp_Object);
+  switch (type)
+    {
+    case CONSTYPE_PURE: cons = pure_cons; break;
+    case CONSTYPE_HEAP: cons = Fcons; break;
+    default: emacs_abort ();
+    }
+
+  eassume (0 < count);
+  Lisp_Object val = cons (arg, Qnil);
+  Lisp_Object tail = val;
+
   va_list ap;
-  ptrdiff_t i;
-  Lisp_Object val, *objp;
-
-  /* Change to SAFE_ALLOCA if you hit this eassert.  */
-  eassert (count <= MAX_ALLOCA / word_size);
-
-  objp = alloca (count * word_size);
-  objp[0] = arg;
   va_start (ap, arg);
-  for (i = 1; i < count; i++)
-    objp[i] = va_arg (ap, Lisp_Object);
-  va_end (ap);
-
-  for (val = Qnil, i = count - 1; i >= 0; i--)
+  for (ptrdiff_t i = 1; i < count; i++)
     {
-      if (type == CONSTYPE_PURE)
-	val = pure_cons (objp[i], val);
-      else if (type == CONSTYPE_HEAP)
-	val = Fcons (objp[i], val);
-      else
-	emacs_abort ();
+      Lisp_Object elem = cons (va_arg (ap, Lisp_Object), Qnil);
+      XSETCDR (tail, elem);
+      tail = elem;
     }
+  va_end (ap);
+
   return val;
 }
 
@@ -3620,7 +3619,7 @@
   p->data[1].object = b;
   return val;
 }
-
+
 #if ! (defined USE_X_TOOLKIT || defined USE_GTK)
 Lisp_Object
 make_save_ptr_ptr (void *a, void *b)

=== modified file 'src/buffer.c'
--- src/buffer.c	2014-09-03 15:10:29 +0000
+++ src/buffer.c	2014-09-05 06:03:28 +0000
@@ -3053,13 +3053,15 @@
   ptrdiff_t end = OVERLAY_POSITION (OVERLAY_END (overlay));
   ptrdiff_t n, i, size;
   Lisp_Object *v, tem;
+  Lisp_Object vbuf[10];
+  USE_SAFE_ALLOCA;
 
-  size = 10;
-  v = alloca (size * sizeof *v);
+  size = ARRAYELTS (vbuf);
+  v = vbuf;
   n = overlays_in (start, end, 0, &v, &size, NULL, NULL);
   if (n > size)
     {
-      v = alloca (n * sizeof *v);
+      SAFE_NALLOCA (v, 1, n);
       overlays_in (start, end, 0, &v, &n, NULL, NULL);
     }
 
@@ -3069,6 +3071,7 @@
 	    !NILP (tem)))
       break;
 
+  SAFE_FREE ();
   return i < n;
 }
 
@@ -4517,13 +4520,13 @@
        First copy the vector contents, in case some of these hooks
        do subsequent modification of the buffer.  */
     ptrdiff_t size = last_overlay_modification_hooks_used;
-    Lisp_Object *copy = alloca (size * sizeof *copy);
+    Lisp_Object *copy;
     ptrdiff_t i;
 
+    USE_SAFE_ALLOCA;
+    SAFE_ALLOCA_LISP (copy, size);
     memcpy (copy, XVECTOR (last_overlay_modification_hooks)->contents,
 	    size * word_size);
-    gcpro1.var = copy;
-    gcpro1.nvars = size;
 
     for (i = 0; i < size;)
       {
@@ -4532,6 +4535,8 @@
 	overlay_i = copy[i++];
 	call_overlay_mod_hooks (prop_i, overlay_i, after, arg1, arg2, arg3);
       }
+
+    SAFE_FREE ();
   }
   UNGCPRO;
 }

=== modified file 'src/buffer.h'
--- src/buffer.h	2014-09-02 11:41:22 +0000
+++ src/buffer.h	2014-09-05 06:03:28 +0000
@@ -1127,15 +1127,15 @@
 #define GET_OVERLAYS_AT(posn, overlays, noverlays, nextp, chrq)		\
   do {									\
     ptrdiff_t maxlen = 40;						\
-    overlays = alloca (maxlen * sizeof *overlays);			\
-    noverlays = overlays_at (posn, false, &overlays, &maxlen,		\
-			     nextp, NULL, chrq);			\
-    if (noverlays > maxlen)						\
+    SAFE_NALLOCA (overlays, 1, maxlen);					\
+    (noverlays) = overlays_at (posn, false, &(overlays), &maxlen,	\
+			       nextp, NULL, chrq);			\
+    if ((noverlays) > maxlen)						\
       {									\
 	maxlen = noverlays;						\
-	overlays = alloca (maxlen * sizeof *overlays);			\
-	noverlays = overlays_at (posn, false, &overlays, &maxlen,	\
-				 nextp, NULL, chrq);			\
+	SAFE_NALLOCA (overlays, 1, maxlen);				\
+	(noverlays) = overlays_at (posn, false, &(overlays), &maxlen,	\
+				   nextp, NULL, chrq);			\
       }									\
   } while (false)
 

=== modified file 'src/callint.c'
--- src/callint.c	2014-06-17 13:50:22 +0000
+++ src/callint.c	2014-09-05 06:03:28 +0000
@@ -297,6 +297,7 @@
   Lisp_Object teml;
   Lisp_Object up_event;
   Lisp_Object enable;
+  USE_SAFE_ALLOCA;
   ptrdiff_t speccount = SPECPDL_INDEX ();
 
   /* The index of the next element of this_command_keys to examine for
@@ -366,12 +367,8 @@
       wrong_type_argument (Qcommandp, function);
   }
 
-  /* If SPECS is set to a string, use it as an interactive prompt.  */
-  if (STRINGP (specs))
-    /* Make a copy of string so that if a GC relocates specs,
-       `string' will still be valid.  */
-    string = xlispstrdupa (specs);
-  else
+  /* If SPECS is not a string, invent one.  */
+  if (! STRINGP (specs))
     {
       Lisp_Object input;
       Lisp_Object funval = Findirect_function (function, Qt);
@@ -416,10 +413,16 @@
 	args[0] = Qfuncall_interactively;
 	args[1] = function;
 	args[2] = specs;
-	return unbind_to (speccount, Fapply (3, args));
+	Lisp_Object result = unbind_to (speccount, Fapply (3, args));
+	SAFE_FREE ();
+	return result;
       }
     }
 
+  /* SPECS is set to a string; use it as an interactive prompt.
+     Copy it so that STRING will be valid even if a GC relocates SPECS.  */
+  SAFE_ALLOCA_STRING (string, specs);
+
   /* Here if function specifies a string to control parsing the defaults.  */
 
   /* Set next_event to point to the first event with parameters.  */
@@ -507,14 +510,15 @@
 	break;
     }
 
-  if (min (MOST_POSITIVE_FIXNUM,
-	   min (PTRDIFF_MAX, SIZE_MAX) / word_size)
-      < nargs)
+  if (MOST_POSITIVE_FIXNUM < min (PTRDIFF_MAX, SIZE_MAX) / word_size
+      && MOST_POSITIVE_FIXNUM < nargs)
     memory_full (SIZE_MAX);
 
-  args = alloca (nargs * sizeof *args);
-  visargs = alloca (nargs * sizeof *visargs);
-  varies = alloca (nargs * sizeof *varies);
+  /* Allocate them all at one go.  This wastes a bit of memory, but
+     it's OK to trade space for speed.  */
+  SAFE_NALLOCA (args, 3, nargs);
+  visargs = args + nargs;
+  varies = (signed char *) (visargs + nargs);
 
   for (i = 0; i < nargs; i++)
     {
@@ -871,7 +875,9 @@
   {
     Lisp_Object val = Ffuncall (nargs, args);
     UNGCPRO;
-    return unbind_to (speccount, val);
+    val = unbind_to (speccount, val);
+    SAFE_FREE ();
+    return val;
   }
 }
 

=== modified file 'src/callproc.c'
--- src/callproc.c	2014-09-02 06:49:40 +0000
+++ src/callproc.c	2014-09-05 06:03:28 +0000
@@ -466,7 +466,7 @@
       && SREF (path, 1) == ':')
     path = Fsubstring (path, make_number (2), Qnil);
 
-  new_argv = SAFE_ALLOCA ((nargs > 4 ? nargs - 2 : 2) * sizeof *new_argv);
+  SAFE_NALLOCA (new_argv, 1, nargs < 4 ? 2 : nargs - 2);
 
   {
     struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
@@ -1151,6 +1151,25 @@
   return new_env;
 }
 
+#ifndef DOS_NT
+
+/* 'exec' failed inside a child running NAME, with error number ERR.
+   Report the error and exit the child.  */
+
+static _Noreturn void
+exec_failed (char const *name, int err)
+{
+  /* Avoid deadlock if the child's perror writes to a full pipe; the
+     pipe's reader is the parent, but with vfork the parent can't
+     run until the child exits.  Truncate the diagnostic instead.  */
+  fcntl (STDERR_FILENO, F_SETFL, O_NONBLOCK);
+
+  errno = err;
+  emacs_perror (name);
+  _exit (err == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
+}
+#endif
+
 /* This is the last thing run in a newly forked inferior
    either synchronous or asynchronous.
    Copy descriptors IN, OUT and ERR as descriptors 0, 1 and 2.
@@ -1174,8 +1193,6 @@
   int cpid;
   HANDLE handles[3];
 #else
-  int exec_errno;
-
   pid_t pid = getpid ();
 #endif /* WINDOWSNT */
 
@@ -1196,6 +1213,8 @@
        on that.  */
     pwd_var = xmalloc (i + 5);
 #else
+    if (MAX_ALLOCA - 5 < i)
+      exec_failed (new_argv[0], ENOMEM);
     pwd_var = alloca (i + 5);
 #endif
     temp = pwd_var + 4;
@@ -1262,6 +1281,8 @@
       }
 
     /* new_length + 2 to include PWD and terminating 0.  */
+    if (MAX_ALLOCA / sizeof *env - 2 < new_length)
+      exec_failed (new_argv[0], ENOMEM);
     env = new_env = alloca ((new_length + 2) * sizeof *env);
     /* If we have a PWD envvar, pass one down,
        but with corrected value.  */
@@ -1270,6 +1291,8 @@
 
     if (STRINGP (display))
       {
+	if (MAX_ALLOCA - sizeof "DISPLAY=" < SBYTES (display))
+	  exec_failed (new_argv[0], ENOMEM);
 	char *vdata = alloca (sizeof "DISPLAY=" + SBYTES (display));
 	strcpy (vdata, "DISPLAY=");
 	strcat (vdata, SSDATA (display));
@@ -1345,16 +1368,7 @@
   tcsetpgrp (0, pid);
 
   execve (new_argv[0], new_argv, env);
-  exec_errno = errno;
-
-  /* Avoid deadlock if the child's perror writes to a full pipe; the
-     pipe's reader is the parent, but with vfork the parent can't
-     run until the child exits.  Truncate the diagnostic instead.  */
-  fcntl (STDERR_FILENO, F_SETFL, O_NONBLOCK);
-
-  errno = exec_errno;
-  emacs_perror (new_argv[0]);
-  _exit (exec_errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
+  exec_failed (new_argv[0], errno);
 
 #else /* MSDOS */
   pid = run_msdos_command (new_argv, pwd_var + 4, in, out, err, env);
@@ -1543,20 +1557,13 @@
 void
 init_callproc (void)
 {
-  char *data_dir = egetenv ("EMACSDATA");
+  bool data_dir = egetenv ("EMACSDATA") != 0;
 
-  register char * sh;
+  char *sh;
   Lisp_Object tempdir;
 #ifdef HAVE_NS
   if (data_dir == 0)
-    {
-      const char *etc_dir = ns_etc_directory ();
-      if (etc_dir)
-        {
-          data_dir = alloca (strlen (etc_dir) + 1);
-          strcpy (data_dir, etc_dir);
-        }
-    }
+    data_dir == ns_etc_directory () != 0;
 #endif
 
   if (!NILP (Vinstallation_directory))

=== modified file 'src/coding.c'
--- src/coding.c	2014-08-11 00:59:34 +0000
+++ src/coding.c	2014-09-05 06:03:28 +0000
@@ -6867,6 +6867,11 @@
 }
 
 
+/* MAX_LOOKUP's maximum value.  MAX_LOOKUP is an int and so cannot
+   exceed INT_MAX.  Also, MAX_LOOKUP is multiplied by sizeof (int) for
+   alloca, so it cannot exceed MAX_ALLOCA / sizeof (int).  */
+enum { MAX_LOOKUP_MAX = min (INT_MAX, MAX_ALLOCA / sizeof (int)) };
+
 /* Return a translation table (or list of them) from coding system
    attribute vector ATTRS for encoding (if ENCODEP) or decoding (if
    not ENCODEP). */
@@ -6919,7 +6924,7 @@
 	{
 	  val = XCHAR_TABLE (translation_table)->extras[1];
 	  if (NATNUMP (val) && *max_lookup < XFASTINT (val))
-	    *max_lookup = XFASTINT (val);
+	    *max_lookup = min (XFASTINT (val), MAX_LOOKUP_MAX);
 	}
       else if (CONSP (translation_table))
 	{
@@ -6931,7 +6936,7 @@
 	      {
 		Lisp_Object tailval = XCHAR_TABLE (XCAR (tail))->extras[1];
 		if (NATNUMP (tailval) && *max_lookup < XFASTINT (tailval))
-		  *max_lookup = XFASTINT (tailval);
+		  *max_lookup = min (XFASTINT (tailval), MAX_LOOKUP_MAX);
 	      }
 	}
     }
@@ -10011,7 +10016,8 @@
 {
   Lisp_Object subsidiaries;
   ptrdiff_t base_name_len = SBYTES (SYMBOL_NAME (base));
-  char *buf = alloca (base_name_len + 6);
+  USE_SAFE_ALLOCA;
+  char *buf = SAFE_ALLOCA (base_name_len + 6);
   int i;
 
   memcpy (buf, SDATA (SYMBOL_NAME (base)), base_name_len);
@@ -10021,6 +10027,7 @@
       strcpy (buf + base_name_len, suffixes[i]);
       ASET (subsidiaries, i, intern (buf));
     }
+  SAFE_FREE ();
   return subsidiaries;
 }
 

=== modified file 'src/doc.c'
--- src/doc.c	2014-04-05 19:30:36 +0000
+++ src/doc.c	2014-09-05 06:03:28 +0000
@@ -561,6 +561,8 @@
   char *p, *name;
   bool skip_file = 0;
   ptrdiff_t count;
+  char const *dirname;
+  ptrdiff_t dirlen;
   /* Preloaded defcustoms using custom-initialize-delay are added to
      this list, but kept unbound.  See http://debbugs.gnu.org/11565  */
   Lisp_Object delayed_init =
@@ -577,15 +579,21 @@
       (0)
 #endif /* CANNOT_DUMP */
     {
-      name = alloca (SCHARS (filename) + 14);
-      strcpy (name, "../etc/");
+      static char const sibling_etc[] = "../etc/";
+      dirname = sibling_etc;
+      dirlen = sizeof sibling_etc - 1;
     }
   else
     {
       CHECK_STRING (Vdoc_directory);
-      name = alloca (SCHARS (filename) + SCHARS (Vdoc_directory) + 1);
-      strcpy (name, SSDATA (Vdoc_directory));
+      dirname = SSDATA (Vdoc_directory);
+      dirlen = SBYTES (Vdoc_directory);
     }
+
+  count = SPECPDL_INDEX ();
+  USE_SAFE_ALLOCA;
+  name = SAFE_ALLOCA (dirlen + SBYTES (filename) + 1);
+  strcpy (name, dirname);
   strcat (name, SSDATA (filename)); 	/*** Add this line ***/
 
   /* Vbuild_files is nil when temacs is run, and non-nil after that.  */
@@ -608,7 +616,6 @@
       report_file_errno ("Opening doc string file", build_string (name),
 			 open_errno);
     }
-  count = SPECPDL_INDEX ();
   record_unwind_protect_int (close_file_unwind, fd);
   Vdoc_file_name = filename;
   filled = 0;
@@ -637,7 +644,7 @@
                   && (end[-1] == 'o' || end[-1] == 'c'))
                 {
                   ptrdiff_t len = end - p - 2;
-                  char *fromfile = alloca (len + 1);
+                  char *fromfile = SAFE_ALLOCA (len + 1);
                   memcpy (fromfile, &p[2], len);
                   fromfile[len] = 0;
                   if (fromfile[len-1] == 'c')
@@ -688,6 +695,8 @@
       filled -= end - buf;
       memmove (buf, end, filled);
     }
+
+  SAFE_FREE ();
   return unbind_to (count, Qnil);
 }
 \f

=== modified file 'src/editfns.c'
--- src/editfns.c	2014-08-07 10:15:52 +0000
+++ src/editfns.c	2014-09-05 06:03:28 +0000
@@ -376,13 +376,14 @@
       set_buffer_temp (XBUFFER (object));
 
       /* First try with room for 40 overlays.  */
-      noverlays = 40;
-      overlay_vec = alloca (noverlays * sizeof *overlay_vec);
+      Lisp_Object overlay_vecbuf[40];
+      noverlays = ARRAYELTS (overlay_vecbuf);
+      overlay_vec = overlay_vecbuf;
       noverlays = overlays_around (posn, overlay_vec, noverlays);
 
       /* If there are more than 40,
 	 make enough space for all, and try again.  */
-      if (noverlays > 40)
+      if (ARRAYELTS (overlay_vecbuf) < noverlays)
 	{
 	  SAFE_ALLOCA_LISP (overlay_vec, noverlays);
 	  noverlays = overlays_around (posn, overlay_vec, noverlays);
@@ -1325,17 +1326,16 @@
   /* Substitute the login name for the &, upcasing the first character.  */
   if (q)
     {
-      register char *r;
-      Lisp_Object login;
-
-      login = Fuser_login_name (make_number (pw->pw_uid));
-      r = alloca (strlen (p) + SCHARS (login) + 1);
+      Lisp_Object login = Fuser_login_name (make_number (pw->pw_uid));
+      USE_SAFE_ALLOCA;
+      char *r = SAFE_ALLOCA (strlen (p) + SBYTES (login) + 1);
       memcpy (r, p, q - p);
       r[q - p] = 0;
       strcat (r, SSDATA (login));
       r[q - p] = upcase ((unsigned char) r[q - p]);
       strcat (r, q + 1);
       full = build_string (r);
+      SAFE_FREE ();
     }
 #endif /* AMPERSAND_FULL_NAME */
 
@@ -3012,8 +3012,12 @@
 check_translation (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t end,
 		   Lisp_Object val)
 {
-  int buf_size = 16, buf_used = 0;
-  int *buf = alloca (sizeof (int) * buf_size);
+  int initial_buf[16];
+  int *buf = initial_buf;
+  ptrdiff_t buf_size = ARRAYELTS (initial_buf);
+  int *bufalloc = 0;
+  ptrdiff_t buf_used = 0;
+  Lisp_Object result = Qnil;
 
   for (; CONSP (val); val = XCDR (val))
     {
@@ -3038,12 +3042,11 @@
 
 		  if (buf_used == buf_size)
 		    {
-		      int *newbuf;
-
-		      buf_size += 16;
-		      newbuf = alloca (sizeof (int) * buf_size);
-		      memcpy (newbuf, buf, sizeof (int) * buf_used);
-		      buf = newbuf;
+		      bufalloc = xpalloc (bufalloc, &buf_size, 1, -1,
+					  sizeof *bufalloc);
+		      if (buf == initial_buf)
+			memcpy (bufalloc, buf, sizeof initial_buf);
+		      buf = bufalloc;
 		    }
 		  buf[buf_used++] = STRING_CHAR_AND_LENGTH (p, len1);
 		  pos_byte += len1;
@@ -3052,10 +3055,15 @@
 		break;
 	    }
 	  if (i == len)
-	    return XCAR (val);
+	    {
+	      result = XCAR (val);
+	      break;
+	    }
 	}
     }
-  return Qnil;
+
+  xfree (bufalloc);
+  return result;
 }
 
 
@@ -4617,11 +4625,11 @@
       if (tmp_interval3)
 	set_text_properties_1 (startr1, endr2, Qnil, buf, tmp_interval3);
 
+      USE_SAFE_ALLOCA;
+
       /* First region smaller than second.  */
       if (len1_byte < len2_byte)
         {
-	  USE_SAFE_ALLOCA;
-
 	  temp = SAFE_ALLOCA (len2_byte);
 
 	  /* Don't precompute these addresses.  We have to compute them
@@ -4633,21 +4641,19 @@
           memcpy (temp, start2_addr, len2_byte);
           memcpy (start1_addr + len2_byte, start1_addr, len1_byte);
           memcpy (start1_addr, temp, len2_byte);
-	  SAFE_FREE ();
         }
       else
 	/* First region not smaller than second.  */
         {
-	  USE_SAFE_ALLOCA;
-
 	  temp = SAFE_ALLOCA (len1_byte);
 	  start1_addr = BYTE_POS_ADDR (start1_byte);
 	  start2_addr = BYTE_POS_ADDR (start2_byte);
           memcpy (temp, start1_addr, len1_byte);
           memcpy (start1_addr, start2_addr, len2_byte);
           memcpy (start1_addr + len2_byte, temp, len1_byte);
-	  SAFE_FREE ();
         }
+
+      SAFE_FREE ();
       graft_intervals_into_buffer (tmp_interval1, start1 + len2,
                                    len1, current_buffer, 0);
       graft_intervals_into_buffer (tmp_interval2, start1,

=== modified file 'src/eval.c'
--- src/eval.c	2014-09-03 04:21:40 +0000
+++ src/eval.c	2014-09-05 06:03:28 +0000
@@ -1272,7 +1272,10 @@
 
   { /* The first clause is the one that should be checked first, so it should
        be added to handlerlist last.  So we build in `clauses' a table that
-       contains `handlers' but in reverse order.  */
+       contains `handlers' but in reverse order.  SAFE_ALLOCA won't work
+       here due to the setjmp, so impose a MAX_ALLOCA limit.  */
+    if (MAX_ALLOCA / word_size < clausenb)
+      memory_full (SIZE_MAX);
     Lisp_Object *clauses = alloca (clausenb * sizeof *clauses);
     Lisp_Object *volatile clauses_volatile = clauses;
     int i = clausenb;
@@ -1311,7 +1314,7 @@
 	    return val;
 	  }
       }
-    }
+  }
 
   val = eval_sub (bodyform);
   handlerlist = oldhandlerlist;
@@ -2789,10 +2792,11 @@
 	val = (XSUBR (fun)->function.aMANY) (numargs, args + 1);
       else
 	{
+	  Lisp_Object internal_argbuf[8];
 	  if (XSUBR (fun)->max_args > numargs)
 	    {
-	      internal_args = alloca (XSUBR (fun)->max_args
-				      * sizeof *internal_args);
+	      eassert (XSUBR (fun)->max_args <= ARRAYELTS (internal_argbuf));
+	      internal_args = internal_argbuf;
 	      memcpy (internal_args, args + 1, numargs * word_size);
 	      for (i = numargs; i < XSUBR (fun)->max_args; i++)
 		internal_args[i] = Qnil;

=== modified file 'src/fileio.c'
--- src/fileio.c	2014-09-02 18:05:00 +0000
+++ src/fileio.c	2014-09-05 06:03:28 +0000
@@ -396,13 +396,6 @@
 Given a Unix syntax file name, returns a string ending in slash.  */)
   (Lisp_Object filename)
 {
-#ifndef DOS_NT
-  register const char *beg;
-#else
-  register char *beg;
-  Lisp_Object tem_fn;
-#endif
-  register const char *p;
   Lisp_Object handler;
 
   CHECK_STRING (filename);
@@ -417,12 +410,8 @@
       return STRINGP (handled_name) ? handled_name : Qnil;
     }
 
-#ifdef DOS_NT
-  beg = xlispstrdupa (filename);
-#else
-  beg = SSDATA (filename);
-#endif
-  p = beg + SBYTES (filename);
+  char *beg = SSDATA (filename);
+  char const *p = beg + SBYTES (filename);
 
   while (p != beg && !IS_DIRECTORY_SEP (p[-1])
 #ifdef DOS_NT
@@ -438,6 +427,11 @@
     return Qnil;
 #ifdef DOS_NT
   /* Expansion of "c:" to drive and default directory.  */
+  Lisp_Object tem_fn;
+  USE_SAFE_ALLOCA;
+  SAFE_ALLOCA_STRING (beg, filename);
+  p = beg + (p - SSDATA (filename));
+
   if (p[-1] == ':')
     {
       /* MAXPATHLEN+1 is guaranteed to be enough space for getdefdir.  */
@@ -481,6 +475,7 @@
       dostounix_filename (beg);
       tem_fn = make_specified_string (beg, -1, p - beg, 0);
     }
+  SAFE_FREE ();
   return tem_fn;
 #else  /* DOS_NT */
   return make_specified_string (beg, -1, p - beg, STRING_MULTIBYTE (filename));
@@ -1019,7 +1014,7 @@
 #endif
 
   /* Make a local copy of NAME to protect it from GC in DECODE_FILE below.  */
-  nm = xlispstrdupa (name);
+  SAFE_ALLOCA_STRING (nm, name);
   nmlim = nm + SBYTES (name);
 
 #ifdef DOS_NT
@@ -1122,12 +1117,12 @@
 	  if (!NILP (Vw32_downcase_file_names))
 	    name = Fdowncase (name);
 #endif
+#else /* not DOS_NT */
+	  if (strcmp (nm, SSDATA (name)) != 0)
+	    name = make_specified_string (nm, -1, nmlim - nm, multibyte);
+#endif /* not DOS_NT */
+	  SAFE_FREE ();
 	  return name;
-#else /* not DOS_NT */
-	  if (strcmp (nm, SSDATA (name)) == 0)
-	    return name;
-	  return make_specified_string (nm, -1, nmlim - nm, multibyte);
-#endif /* not DOS_NT */
 	}
     }
 
@@ -1729,7 +1724,8 @@
 	  for (s = p; *s && !IS_DIRECTORY_SEP (*s); s++);
 	  if (p[0] == '~' && s > p + 1)	/* We've got "/~something/".  */
 	    {
-	      char *o = alloca (s - p + 1);
+	      USE_SAFE_ALLOCA;
+	      char *o = SAFE_ALLOCA (s - p + 1);
 	      struct passwd *pw;
 	      memcpy (o, p, s - p);
 	      o [s - p] = 0;
@@ -1740,6 +1736,7 @@
 	      block_input ();
 	      pw = getpwnam (o + 1);
 	      unblock_input ();
+	      SAFE_FREE ();
 	      if (pw)
 		return p;
 	    }
@@ -1788,7 +1785,8 @@
   /* Always work on a copy of the string, in case GC happens during
      decode of environment variables, causing the original Lisp_String
      data to be relocated.  */
-  nm = xlispstrdupa (filename);
+  USE_SAFE_ALLOCA;
+  SAFE_ALLOCA_STRING (nm, filename);
 
 #ifdef DOS_NT
   dostounix_filename (nm);
@@ -1802,8 +1800,13 @@
     /* Start over with the new string, so we check the file-name-handler
        again.  Important with filenames like "/home/foo//:/hello///there"
        which would substitute to "/:/hello///there" rather than "/there".  */
-    return Fsubstitute_in_file_name
-      (make_specified_string (p, -1, endp - p, multibyte));
+    {
+      Lisp_Object result
+	= (Fsubstitute_in_file_name
+	   (make_specified_string (p, -1, endp - p, multibyte)));
+      SAFE_FREE ();
+      return result;
+    }
 
   /* See if any variables are substituted into the string.  */
 
@@ -1825,6 +1828,7 @@
       if (!NILP (Vw32_downcase_file_names))
 	filename = Fdowncase (filename);
 #endif
+      SAFE_FREE ();
       return filename;
     }
 
@@ -1843,14 +1847,14 @@
     {
       Lisp_Object xname = make_specified_string (xnm, -1, x - xnm, multibyte);
 
-      xname = Fdowncase (xname);
-      return xname;
+      filename = Fdowncase (xname);
     }
   else
 #endif
-  return (xnm == SSDATA (filename)
-	  ? filename
-	  : make_specified_string (xnm, -1, x - xnm, multibyte));
+  if (xnm != SSDATA (filename))
+    filename = make_specified_string (xnm, -1, x - xnm, multibyte);
+  SAFE_FREE ();
+  return filename;
 }
 \f
 /* A slightly faster and more convenient way to get

=== modified file 'src/fns.c'
--- src/fns.c	2014-08-30 23:29:23 +0000
+++ src/fns.c	2014-09-05 06:03:28 +0000
@@ -1992,17 +1992,14 @@
     return;
   ptrdiff_t halflen = len >> 1;
   Lisp_Object *tmp;
-  Lisp_Object tmpvec = Qnil;
-  struct gcpro gcpro1, gcpro2, gcpro3;
-  GCPRO3 (vector, predicate, tmpvec);
-  if (halflen < MAX_ALLOCA / word_size)
-    tmp = alloca (halflen * word_size);
-  else
-    {
-      tmpvec = Fmake_vector (make_number (halflen), make_number (0));
-      tmp = XVECTOR (tmpvec)->contents;
-    }
+  struct gcpro gcpro1, gcpro2;
+  GCPRO2 (vector, predicate);
+  USE_SAFE_ALLOCA;
+  SAFE_ALLOCA_LISP (tmp, halflen);
+  for (ptrdiff_t i = 0; i < halflen; i++)
+    tmp[i] = make_number (0);
   sort_vector_inplace (predicate, len, XVECTOR (vector)->contents, tmp);
+  SAFE_FREE ();
   UNGCPRO;
 }
 
@@ -3289,7 +3286,6 @@
   if (encoded_length < 0)
     {
       /* The encoding wasn't possible. */
-      SAFE_FREE ();
       error ("Multibyte character in data for base64 encoding");
     }
 
@@ -3434,7 +3430,6 @@
   if (decoded_length < 0)
     {
       /* The decoding wasn't possible. */
-      SAFE_FREE ();
       error ("Invalid base64 data");
     }
 
@@ -4581,12 +4576,12 @@
 {
   Lisp_Object test, size, rehash_size, rehash_threshold, weak;
   struct hash_table_test testdesc;
-  char *used;
   ptrdiff_t i;
+  USE_SAFE_ALLOCA;
 
   /* The vector `used' is used to keep track of arguments that
      have been consumed.  */
-  used = alloca (nargs * sizeof *used);
+  char *used = SAFE_ALLOCA (nargs * sizeof *used);
   memset (used, 0, nargs * sizeof *used);
 
   /* See if there's a `:test TEST' among the arguments.  */
@@ -4653,6 +4648,7 @@
     if (!used[i])
       signal_error ("Invalid argument list", args[i]);
 
+  SAFE_FREE ();
   return make_hash_table (testdesc, size, rehash_size, rehash_threshold, weak);
 }
 

=== modified file 'src/font.c'
--- src/font.c	2014-07-26 13:17:25 +0000
+++ src/font.c	2014-09-05 06:03:28 +0000
@@ -1299,6 +1299,9 @@
 
   val = AREF (font, FONT_SIZE_INDEX);
   eassert (NUMBERP (val) || NILP (val));
+  char font_size_index_buf[sizeof "-*"
+			   + MAX (INT_STRLEN_BOUND (EMACS_INT),
+				  1 + DBL_MAX_10_EXP + 1)];
   if (INTEGERP (val))
     {
       EMACS_INT v = XINT (val);
@@ -1306,8 +1309,7 @@
 	v = pixel_size;
       if (v > 0)
 	{
-	  f[XLFD_PIXEL_INDEX] = p =
-	    alloca (sizeof "-*" + INT_STRLEN_BOUND (EMACS_INT));
+	  f[XLFD_PIXEL_INDEX] = p = font_size_index_buf;
 	  sprintf (p, "%"pI"d-*", v);
 	}
       else
@@ -1316,21 +1318,22 @@
   else if (FLOATP (val))
     {
       double v = XFLOAT_DATA (val) * 10;
-      f[XLFD_PIXEL_INDEX] = p = alloca (sizeof "*-" + 1 + DBL_MAX_10_EXP + 1);
+      f[XLFD_PIXEL_INDEX] = p = font_size_index_buf;
       sprintf (p, "*-%.0f", v);
     }
   else
     f[XLFD_PIXEL_INDEX] = "*-*";
 
+  char dpi_index_buf[sizeof "-" + 2 * INT_STRLEN_BOUND (EMACS_INT)];
   if (INTEGERP (AREF (font, FONT_DPI_INDEX)))
     {
       EMACS_INT v = XINT (AREF (font, FONT_DPI_INDEX));
-      f[XLFD_RESX_INDEX] = p =
-	alloca (sizeof "-" + 2 * INT_STRLEN_BOUND (EMACS_INT));
+      f[XLFD_RESX_INDEX] = p = dpi_index_buf;
       sprintf (p, "%"pI"d-%"pI"d", v, v);
     }
   else
     f[XLFD_RESX_INDEX] = "*-*";
+
   if (INTEGERP (AREF (font, FONT_SPACING_INDEX)))
     {
       EMACS_INT spacing = XINT (AREF (font, FONT_SPACING_INDEX));
@@ -1342,13 +1345,16 @@
     }
   else
     f[XLFD_SPACING_INDEX] = "*";
+
+  char avgwidth_index_buf[INT_BUFSIZE_BOUND (EMACS_INT)];
   if (INTEGERP (AREF (font,  FONT_AVGWIDTH_INDEX)))
     {
-      f[XLFD_AVGWIDTH_INDEX] = p = alloca (INT_BUFSIZE_BOUND (EMACS_INT));
+      f[XLFD_AVGWIDTH_INDEX] = p = avgwidth_index_buf;
       sprintf (p, "%"pI"d", XINT (AREF (font, FONT_AVGWIDTH_INDEX)));
     }
   else
     f[XLFD_AVGWIDTH_INDEX] = "*";
+
   len = snprintf (name, nbytes, "-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s",
 		  f[XLFD_FOUNDRY_INDEX], f[XLFD_FAMILY_INDEX],
 		  f[XLFD_WEIGHT_INDEX], f[XLFD_SLANT_INDEX],
@@ -2185,13 +2191,17 @@
 static Lisp_Object
 font_vconcat_entity_vectors (Lisp_Object list)
 {
-  int nargs = XINT (Flength (list));
-  Lisp_Object *args = alloca (word_size * nargs);
-  int i;
+  EMACS_INT nargs = XFASTINT (Flength (list));
+  Lisp_Object *args;
+  USE_SAFE_ALLOCA;
+  SAFE_ALLOCA_LISP (args, nargs);
+  ptrdiff_t i;
 
   for (i = 0; i < nargs; i++, list = XCDR (list))
     args[i] = XCAR (list);
-  return Fvconcat (nargs, args);
+  Lisp_Object result = Fvconcat (nargs, args);
+  SAFE_FREE ();
+  return result;
 }
 
 
@@ -3219,9 +3229,10 @@
       val = attrs[LFACE_FAMILY_INDEX];
       val = font_intern_prop (SSDATA (val), SBYTES (val), 1);
     }
+  Lisp_Object familybuf[3];
   if (NILP (val))
     {
-      family = alloca ((sizeof family[0]) * 2);
+      family = familybuf;
       family[0] = Qnil;
       family[1] = zero_vector;	/* terminator.  */
     }
@@ -3242,7 +3253,7 @@
 	}
       else
 	{
-	  family = alloca ((sizeof family[0]) * 3);
+	  family = familybuf;
 	  i = 0;
 	  family[i++] = val;
 	  if (NILP (AREF (spec, FONT_FAMILY_INDEX)))
@@ -3529,8 +3540,9 @@
       struct font_driver_list **list_table, **next;
       Lisp_Object tail;
       int i;
+      USE_SAFE_ALLOCA;
 
-      list_table = alloca (sizeof list_table[0] * (num_font_drivers + 1));
+      SAFE_NALLOCA (list_table, 1, num_font_drivers + 1);
       for (i = 0, tail = new_drivers; ! NILP (tail); tail = XCDR (tail))
 	{
 	  for (list = f->font_driver_list; list; list = list->next)
@@ -3551,6 +3563,7 @@
 	  next = &(*next)->next;
 	}
       *next = NULL;
+      SAFE_FREE ();
 
       if (! f->font_driver_list->on)
 	{ /* None of the drivers is enabled: enable them all.

=== modified file 'src/fontset.c'
--- src/fontset.c	2014-08-11 00:59:34 +0000
+++ src/fontset.c	2014-09-05 06:03:28 +0000
@@ -1079,10 +1079,11 @@
       /* If PATTERN is not full XLFD we convert "*" to ".*".  Otherwise
 	 we convert "*" to "[^-]*" which is much faster in regular
 	 expression matching.  */
-      if (ndashes < 14)
-	p1 = regex = alloca (SBYTES (pattern) + 2 * nstars + 2 * nescs + 1);
-      else
-	p1 = regex = alloca (SBYTES (pattern) + 5 * nstars + 2 * nescs + 1);
+      ptrdiff_t regexsize = (SBYTES (pattern)
+			     + (ndashes < 14 ? 2 : 5) * nstars
+			     + 2 * nescs + 1);
+      USE_SAFE_ALLOCA;
+      p1 = regex = SAFE_ALLOCA (regexsize);
 
       *p1++ = '^';
       for (p0 = SDATA (pattern); *p0; p0++)
@@ -1110,6 +1111,7 @@
 
       Vcached_fontset_data = Fcons (build_string (SSDATA (pattern)),
 				    build_string ((char *) regex));
+      SAFE_FREE ();
     }
 
   return CACHED_FONTSET_REGEX;
@@ -1892,7 +1894,9 @@
 
   /* Recode fontsets realized on FRAME from the base fontset FONTSET
      in the table `realized'.  */
-  realized[0] = alloca (word_size * ASIZE (Vfontset_table));
+  USE_SAFE_ALLOCA;
+  SAFE_ALLOCA_LISP (realized[0], 2 * ASIZE (Vfontset_table));
+  realized[1] = realized[0] + ASIZE (Vfontset_table);
   for (i = j = 0; i < ASIZE (Vfontset_table); i++)
     {
       elt = FONTSET_FROM_ID (i);
@@ -1903,7 +1907,6 @@
     }
   realized[0][j] = Qnil;
 
-  realized[1] = alloca (word_size * ASIZE (Vfontset_table));
   for (i = j = 0; ! NILP (realized[0][i]); i++)
     {
       elt = FONTSET_DEFAULT (realized[0][i]);
@@ -1995,6 +1998,7 @@
 	break;
     }
 
+  SAFE_FREE ();
   return tables[0];
 }
 

=== modified file 'src/frame.c'
--- src/frame.c	2014-09-03 15:10:29 +0000
+++ src/frame.c	2014-09-05 06:03:28 +0000
@@ -994,22 +994,24 @@
     {
       char *name = 0, *type = 0;
       Lisp_Object tty, tty_type;
+      USE_SAFE_ALLOCA;
 
       tty = get_future_frame_param
         (Qtty, parms, (FRAME_TERMCAP_P (XFRAME (selected_frame))
                        ? FRAME_TTY (XFRAME (selected_frame))->name
                        : NULL));
       if (!NILP (tty))
-	name = xlispstrdupa (tty);
+	SAFE_ALLOCA_STRING (name, tty);
 
       tty_type = get_future_frame_param
         (Qtty_type, parms, (FRAME_TERMCAP_P (XFRAME (selected_frame))
                             ? FRAME_TTY (XFRAME (selected_frame))->type
                             : NULL));
       if (!NILP (tty_type))
-	type = xlispstrdupa (tty_type);
+	SAFE_ALLOCA_STRING (type, tty_type);
 
       t = init_tty (name, type, 0); /* Errors are not fatal.  */
+      SAFE_FREE ();
     }
 
   f = make_terminal_frame (t);
@@ -3017,14 +3019,14 @@
 #ifdef HAVE_X_WINDOWS
   bool icon_left_no_change = 0, icon_top_no_change = 0;
 #endif
-  struct gcpro gcpro1, gcpro2;
 
   i = 0;
   for (tail = alist; CONSP (tail); tail = XCDR (tail))
     i++;
 
-  parms = alloca (i * sizeof *parms);
-  values = alloca (i * sizeof *values);
+  USE_SAFE_ALLOCA;
+  SAFE_ALLOCA_LISP (parms, 2 * i);
+  values = parms + i;
 
   /* Extract parm names and values into those vectors.  */
 
@@ -3041,10 +3043,6 @@
   /* TAIL and ALIST are not used again below here.  */
   alist = tail = Qnil;
 
-  GCPRO2 (*parms, *values);
-  gcpro1.nvars = i;
-  gcpro2.nvars = i;
-
   /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
      because their values appear in VALUES and strings are not valid.  */
   top = left = Qunbound;
@@ -3273,7 +3271,7 @@
 #endif /* HAVE_X_WINDOWS */
   }
 
-  UNGCPRO;
+  SAFE_FREE ();
 }
 
 
@@ -4010,10 +4008,6 @@
 static Lisp_Object
 xrdb_get_resource (XrmDatabase rdb, Lisp_Object attribute, Lisp_Object class, Lisp_Object component, Lisp_Object subclass)
 {
-  register char *value;
-  char *name_key;
-  char *class_key;
-
   CHECK_STRING (attribute);
   CHECK_STRING (class);
 
@@ -4028,17 +4022,20 @@
 
   /* Allocate space for the components, the dots which separate them,
      and the final '\0'.  Make them big enough for the worst case.  */
-  name_key = alloca (SBYTES (Vx_resource_name)
-		     + (STRINGP (component)
-			? SBYTES (component) : 0)
-		     + SBYTES (attribute)
-		     + 3);
+  ptrdiff_t name_keysize = (SBYTES (Vx_resource_name)
+			    + (STRINGP (component)
+			       ? SBYTES (component) : 0)
+			    + SBYTES (attribute)
+			    + 3);
 
-  class_key = alloca (SBYTES (Vx_resource_class)
-		      + SBYTES (class)
-		      + (STRINGP (subclass)
-			 ? SBYTES (subclass) : 0)
-		      + 3);
+  ptrdiff_t class_keysize = (SBYTES (Vx_resource_class)
+			     + SBYTES (class)
+			     + (STRINGP (subclass)
+				? SBYTES (subclass) : 0)
+			     + 3);
+  USE_SAFE_ALLOCA;
+  char *name_key = SAFE_ALLOCA (name_keysize + class_keysize);
+  char *class_key = name_key + name_keysize;
 
   /* Start with emacs.FRAMENAME for the name (the specific one)
      and with `Emacs' for the class key (the general one).  */
@@ -4060,7 +4057,8 @@
   strcat (name_key, ".");
   strcat (name_key, SSDATA (attribute));
 
-  value = x_get_string_resource (rdb, name_key, class_key);
+  char *value = x_get_string_resource (rdb, name_key, class_key);
+  SAFE_FREE();
 
   if (value && *value)
     return build_string (value);
@@ -4112,8 +4110,10 @@
 
   /* Allocate space for the components, the dots which separate them,
      and the final '\0'.  */
-  char *name_key = SAFE_ALLOCA (invocation_namelen + strlen (attribute) + 2);
-  char *class_key = alloca ((sizeof (EMACS_CLASS) - 1) + strlen (class) + 2);
+  ptrdiff_t name_keysize = invocation_namelen + strlen (attribute) + 2;
+  ptrdiff_t class_keysize = sizeof (EMACS_CLASS) - 1 + strlen (class) + 2;
+  char *name_key = SAFE_ALLOCA (name_keysize + class_keysize);
+  char *class_key = name_key + name_keysize;
 
   esprintf (name_key, "%s.%s", SSDATA (Vinvocation_name), attribute);
   sprintf (class_key, "%s.%s", EMACS_CLASS, class);

=== modified file 'src/ftfont.c'
--- src/ftfont.c	2014-08-25 07:00:42 +0000
+++ src/ftfont.c	2014-09-05 06:03:28 +0000
@@ -24,6 +24,8 @@
 #include <fontconfig/fontconfig.h>
 #include <fontconfig/fcfreetype.h>
 
+#include <c-strcase.h>
+
 #include "lisp.h"
 #include "dispextern.h"
 #include "frame.h"
@@ -140,6 +142,12 @@
     { NULL }
   };
 
+static bool
+matching_prefix (char const *str, ptrdiff_t len, char const *pat)
+{
+  return len == strlen (pat) && c_strncasecmp (str, pat, len) == 0;
+}
+
 /* Dirty hack for handing ADSTYLE property.
 
    Fontconfig (actually the underlying FreeType) gives such ADSTYLE
@@ -171,18 +179,10 @@
     return Qnil;
   str = (char *) fcstr;
   for (end = str; *end && *end != ' '; end++);
-  if (*end)
-    {
-      char *newstr = alloca (end - str + 1);
-      memcpy (newstr, str, end - str);
-      newstr[end - str] = '\0';
-      end = newstr + (end - str);
-      str = newstr;
-    }
-  if (xstrcasecmp (str, "Regular") == 0
-      || xstrcasecmp (str, "Bold") == 0
-      || xstrcasecmp (str, "Oblique") == 0
-      || xstrcasecmp (str, "Italic") == 0)
+  if (matching_prefix (str, end - str, "Regular")
+      || matching_prefix (str, end - str, "Bold")
+      || matching_prefix (str, end - str, "Oblique")
+      || matching_prefix (str, end - str, "Italic"))
     return Qnil;
   adstyle = font_intern_prop (str, end - str, 1);
   if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
@@ -573,7 +573,8 @@
 ftfont_get_charset (Lisp_Object registry)
 {
   char *str = SSDATA (SYMBOL_NAME (registry));
-  char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
+  USE_SAFE_ALLOCA;
+  char *re = SAFE_ALLOCA (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
   Lisp_Object regexp;
   int i, j;
 
@@ -589,6 +590,7 @@
     }
   re[j] = '\0';
   regexp = make_unibyte_string (re, j);
+  SAFE_FREE ();
   for (i = 0; fc_charset_table[i].name; i++)
     if (fast_c_string_match_ignore_case
 	(regexp, fc_charset_table[i].name,
@@ -1688,7 +1690,8 @@
 	else if (! otf)
 	  return 0;
 	for (n = 1; spec->features[i][n]; n++);
-	tags = alloca (sizeof (OTF_Tag) * n);
+	USE_SAFE_ALLOCA;
+	SAFE_NALLOCA (tags, 1, n);
 	for (n = 0, negative = 0; spec->features[i][n]; n++)
 	  {
 	    if (spec->features[i][n] == 0xFFFFFFFF)
@@ -1698,16 +1701,17 @@
 	    else
 	      tags[n] = spec->features[i][n];
 	  }
-#ifdef M17N_FLT_USE_NEW_FEATURE
-	if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
-				tags, n - negative) != 1)
-	  return 0;
-#else  /* not M17N_FLT_USE_NEW_FEATURE */
-	if (n - negative > 0
-	    && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
-				   tags, n - negative) != 1)
-	  return 0;
-#endif	/* not M17N_FLT_USE_NEW_FEATURE */
+	bool passed = true;
+#ifndef M17N_FLT_USE_NEW_FEATURE
+	passed = n - negative > 0;
+#endif
+	if (passed)
+	  passed = (OTF_check_features (otf, i == 0, spec->script,
+					spec->langsys, tags, n - negative)
+		    != 1);
+	SAFE_FREE ();
+	if (passed)
+	  return 0;
       }
   return 1;
 #undef FEATURE_NONE
@@ -1799,11 +1803,15 @@
   if (len == 0)
     return from;
   OTF_tag_name (spec->script, script);
+
+  char langsysbuf[5];
   if (spec->langsys)
     {
-      langsys = alloca (5);
+      langsys = langsysbuf;
       OTF_tag_name (spec->langsys, langsys);
     }
+
+  USE_SAFE_ALLOCA;
   for (i = 0; i < 2; i++)
     {
       char *p;
@@ -1811,10 +1819,11 @@
       if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
 	{
 	  for (j = 0; spec->features[i][j]; j++);
+	  SAFE_NALLOCA (p, 6, j);
 	  if (i == 0)
-	    p = gsub_features = alloca (6 * j);
+	    gsub_features = p;
 	  else
-	    p = gpos_features = alloca (6 * j);
+	    gpos_features = p;
 	  for (j = 0; spec->features[i][j]; j++)
 	    {
 	      if (spec->features[i][j] == 0xFFFFFFFF)
@@ -1846,7 +1855,10 @@
 				   gsub_features) < 0)
 	goto simple_copy;
       if (out->allocated < out->used + otf_gstring.used)
-	return -2;
+	{
+	  SAFE_FREE ();
+	  return -2;
+	}
       features = otf->gsub->FeatureList.Feature;
       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
 	{
@@ -1935,7 +1947,10 @@
   else if (out)
     {
       if (out->allocated < out->used + len)
-	return -2;
+	{
+	  SAFE_FREE ();
+	  return -2;
+	}
       for (i = 0; i < len; i++)
 	out->glyphs[out->used++] = in->glyphs[from + i];
     }
@@ -1947,7 +1962,10 @@
 
       if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
 				   gpos_features) < 0)
-	return to;
+	{
+	  SAFE_FREE ();
+	  return to;
+	}
       features = otf->gpos->FeatureList.Feature;
       x_ppem = ft_face->size->metrics.x_ppem;
       y_ppem = ft_face->size->metrics.y_ppem;
@@ -2069,7 +2087,10 @@
     {
       if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
 				   gpos_features) < 0)
-	return to;
+	{
+	  SAFE_FREE ();
+	  return to;
+	}
       features = otf->gpos->FeatureList.Feature;
       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
 	   i++, otfg++)
@@ -2089,9 +2110,11 @@
 	      }
 	  }
     }
+  SAFE_FREE ();
   return to;
 
  simple_copy:
+  SAFE_FREE ();
   if (! out)
     return to;
   if (out->allocated < out->used + len)
@@ -2129,11 +2152,15 @@
   if (len == 0)
     return from;
   OTF_tag_name (spec->script, script);
+
+  char langsysbuf[5];
   if (spec->langsys)
     {
-      langsys = alloca (5);
+      langsys = langsysbuf;
       OTF_tag_name (spec->langsys, langsys);
     }
+
+  USE_SAFE_ALLOCA;
   for (i = 0; i < 2; i++)
     {
       char *p;
@@ -2141,10 +2168,11 @@
       if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
 	{
 	  for (j = 0; spec->features[i][j]; j++);
+	  SAFE_NALLOCA (p, 6, j);
 	  if (i == 0)
-	    p = gsub_features = alloca (6 * j);
+	    gsub_features = p;
 	  else
-	    p = gpos_features = alloca (6 * j);
+	    gpos_features = p;
 	  for (j = 0; spec->features[i][j]; j++)
 	    {
 	      if (spec->features[i][j] == 0xFFFFFFFF)
@@ -2176,7 +2204,10 @@
 	  < 0)
 	goto simple_copy;
       if (out->allocated < out->used + otf_gstring.used)
-	return -2;
+	{
+	  SAFE_FREE ();
+	  return -2;
+	}
       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
 	{
 	  MFLTGlyph *g;
@@ -2227,7 +2258,10 @@
   else
     {
       if (out->allocated < out->used + len)
-	return -2;
+	{
+	  SAFE_FREE ();
+	  return -2;
+	}
       for (i = 0; i < len; i++)
 	out->glyphs[out->used++] = in->glyphs[from + i];
     }
@@ -2239,7 +2273,10 @@
 
       if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
 	  < 0)
-	return to;
+	{
+	  SAFE_FREE ();
+	  return to;
+	}
 
       x_ppem = ft_face->size->metrics.x_ppem;
       y_ppem = ft_face->size->metrics.y_ppem;
@@ -2349,9 +2386,11 @@
 	    base = g;
 	}
     }
+  SAFE_FREE ();
   return to;
 
  simple_copy:
+  SAFE_FREE ();
   if (out->allocated < out->used + len)
     return -2;
   font->get_metrics (font, in, from, to);

=== modified file 'src/ftxfont.c'
--- src/ftxfont.c	2014-07-03 12:20:00 +0000
+++ src/ftxfont.c	2014-09-05 06:03:28 +0000
@@ -271,10 +271,11 @@
 
   n[0] = n[1] = n[2] = n[3] = n[4] = n[5] = n[6] = 0;
 
+  USE_SAFE_ALLOCA;
+  SAFE_NALLOCA (code, 1, len);
   block_input ();
   if (with_background)
     ftxfont_draw_background (f, font, s->gc, x, y, s->width);
-  code = alloca (sizeof (unsigned) * len);
   for (i = 0; i < len; i++)
     code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
 	       | XCHAR2B_BYTE2 (s->char2b + from + i));
@@ -322,6 +323,7 @@
     }
 
   unblock_input ();
+  SAFE_FREE ();
 
   return len;
 }

=== modified file 'src/image.c'
--- src/image.c	2014-07-07 23:25:13 +0000
+++ src/image.c	2014-09-05 06:03:28 +0000
@@ -3037,13 +3037,16 @@
 				     + SBYTES (data)));
       else
 	{
+	  USE_SAFE_ALLOCA;
+
 	  if (VECTORP (data))
 	    {
 	      int i;
 	      char *p;
 	      int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
 
-	      p = bits = alloca (nbytes * img->height);
+	      SAFE_NALLOCA (bits, nbytes, img->height);
+	      p = bits;
 	      for (i = 0; i < img->height; ++i, p += nbytes)
 		{
 		  Lisp_Object line = AREF (data, i);
@@ -3064,9 +3067,8 @@
             int nbytes, i;
             /* Windows mono bitmaps are reversed compared with X.  */
             invertedBits = bits;
-            nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR
-              * img->height;
-            bits = alloca (nbytes);
+            nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
+            SAFE_NALLOCA (bits, nbytes, img->height);
             for (i = 0; i < nbytes; i++)
               bits[i] = XBM_BIT_SHUFFLE (invertedBits[i]);
           }
@@ -3088,6 +3090,8 @@
 			   img->spec, Qnil);
 	      x_clear_image (f, img);
 	    }
+
+	  SAFE_FREE ();
 	}
     }
 
@@ -3494,6 +3498,8 @@
   int rc;
   XpmAttributes attrs;
   Lisp_Object specified_file, color_symbols;
+  USE_SAFE_ALLOCA;
+
 #ifdef HAVE_NTGUI
   HDC hdc;
   xpm_XImage * xpm_image = NULL, * xpm_mask = NULL;
@@ -3536,7 +3542,7 @@
     {
       Lisp_Object tail;
       XpmColorSymbol *xpm_syms;
-      int i, size;
+      ptrdiff_t i, size;
 
       attrs.valuemask |= XpmColorSymbols;
 
@@ -3546,8 +3552,8 @@
 	++attrs.numsymbols;
 
       /* Allocate an XpmColorSymbol array.  */
+      SAFE_NALLOCA (xpm_syms, 1, attrs.numsymbols);
       size = attrs.numsymbols * sizeof *xpm_syms;
-      xpm_syms = alloca (size);
       memset (xpm_syms, 0, size);
       attrs.colorsymbols = xpm_syms;
 
@@ -3569,17 +3575,11 @@
 	  name = XCAR (XCAR (tail));
 	  color = XCDR (XCAR (tail));
 	  if (STRINGP (name))
-	    {
-	      xpm_syms[i].name = alloca (SCHARS (name) + 1);
-	      strcpy (xpm_syms[i].name, SSDATA (name));
-	    }
+	    SAFE_ALLOCA_STRING (xpm_syms[i].name, name);
 	  else
 	    xpm_syms[i].name = empty_string;
 	  if (STRINGP (color))
-	    {
-	      xpm_syms[i].value = alloca (SCHARS (color) + 1);
-	      strcpy (xpm_syms[i].value, SSDATA (color));
-	    }
+	    SAFE_ALLOCA_STRING (xpm_syms[i].value, color);
 	  else
 	    xpm_syms[i].value = empty_string;
 	}
@@ -3610,6 +3610,7 @@
 #ifdef ALLOC_XPM_COLORS
 	  xpm_free_color_cache ();
 #endif
+	  SAFE_FREE ();
 	  return 0;
 	}
 
@@ -3640,6 +3641,7 @@
 #ifdef ALLOC_XPM_COLORS
 	  xpm_free_color_cache ();
 #endif
+	  SAFE_FREE ();
 	  return 0;
 	}
 #ifdef HAVE_NTGUI
@@ -3782,6 +3784,7 @@
 #ifdef ALLOC_XPM_COLORS
   xpm_free_color_cache ();
 #endif
+  SAFE_FREE ();
   return rc == XpmSuccess;
 }
 
@@ -6580,6 +6583,7 @@
      colors generated, and mgr->cinfo.colormap is a two-dimensional array
      of color indices in the range 0..mgr->cinfo.actual_number_of_colors.
      No more than 255 colors will be generated.  */
+  USE_SAFE_ALLOCA;
   {
     int i, ir, ig, ib;
 
@@ -6595,7 +6599,7 @@
        a default color, and we don't have to care about which colors
        can be freed safely, and which can't.  */
     init_color_table ();
-    colors = alloca (mgr->cinfo.actual_number_of_colors * sizeof *colors);
+    SAFE_NALLOCA (colors, 1, mgr->cinfo.actual_number_of_colors);
 
     for (i = 0; i < mgr->cinfo.actual_number_of_colors; ++i)
       {
@@ -6638,6 +6642,7 @@
 
   /* Put ximg into the image.  */
   image_put_x_image (f, img, ximg, 0);
+  SAFE_FREE ();
   return 1;
 }
 

=== modified file 'src/keyboard.c'
--- src/keyboard.c	2014-08-27 10:51:21 +0000
+++ src/keyboard.c	2014-09-05 06:03:28 +0000
@@ -500,10 +500,12 @@
 static void
 echo_add_key (Lisp_Object c)
 {
-  int size = KEY_DESCRIPTION_SIZE + 100;
-  char *buffer = alloca (size);
+  char initbuf[KEY_DESCRIPTION_SIZE + 100];
+  ptrdiff_t size = sizeof initbuf;
+  char *buffer = initbuf;
   char *ptr = buffer;
   Lisp_Object echo_string;
+  USE_SAFE_ALLOCA;
 
   echo_string = KVAR (current_kboard, echo_string);
 
@@ -515,13 +517,13 @@
   else if (SYMBOLP (c))
     {
       Lisp_Object name = SYMBOL_NAME (c);
-      int nbytes = SBYTES (name);
+      ptrdiff_t nbytes = SBYTES (name);
 
       if (size - (ptr - buffer) < nbytes)
 	{
-	  int offset = ptr - buffer;
+	  ptrdiff_t offset = ptr - buffer;
 	  size = max (2 * size, size + nbytes);
-	  buffer = alloca (size);
+	  buffer = SAFE_ALLOCA (size);
 	  ptr = buffer + offset;
 	}
 
@@ -532,14 +534,14 @@
   if ((NILP (echo_string) || SCHARS (echo_string) == 0)
       && help_char_p (c))
     {
-      const char *text = " (Type ? for further options)";
-      int len = strlen (text);
+      static const char text[] = " (Type ? for further options)";
+      int len = sizeof text - 1;
 
       if (size - (ptr - buffer) < len)
 	{
-	  int offset = ptr - buffer;
+	  ptrdiff_t offset = ptr - buffer;
 	  size += len;
-	  buffer = alloca (size);
+	  buffer = SAFE_ALLOCA (size);
 	  ptr = buffer + offset;
 	}
 
@@ -572,6 +574,7 @@
   kset_echo_string
     (current_kboard,
      concat2 (echo_string, make_string (buffer, ptr - buffer)));
+  SAFE_FREE ();
 }
 
 /* Add C to the echo string, if echoing is going on.  C can be a
@@ -1147,7 +1150,7 @@
 Lisp_Object
 command_loop (void)
 {
-#ifdef HAVE_STACK_OVERFLOW_HANDLING
+#ifdef HAVE_STACK_OVERFLOW_HANDLING
   /* At least on GNU/Linux, saving signal mask is important here.  */
   if (sigsetjmp (return_to_command_loop, 1) != 0)
     {
@@ -2351,14 +2354,15 @@
 	    { /* An encoded byte sequence, let's try to decode it.  */
 	      struct coding_system *coding
 		= TERMINAL_KEYBOARD_CODING (terminal);
-	      unsigned char *src = alloca (n);
+	      unsigned char src[MAX_ENCODED_BYTES];
+	      unsigned char dest[4 * sizeof src];
 	      int i;
 	      for (i = 0; i < n; i++)
 		src[i] = XINT (events[i]);
 	      if (meta_key != 2)
 		for (i = 0; i < n; i++)
 		  src[i] &= ~0x80;
-	      coding->destination = alloca (n * 4);
+	      coding->destination = dest;
 	      coding->dst_bytes = n * 4;
 	      decode_coding_c_string (coding, src, n, Qnil);
 	      eassert (coding->produced_char <= n);
@@ -7434,11 +7438,14 @@
      in the current keymaps, or nil where it is not a prefix.  */
   Lisp_Object *maps;
 
+  Lisp_Object mapsbuf[3];
   Lisp_Object def, tail;
 
   ptrdiff_t mapno;
   Lisp_Object oquit;
 
+  USE_SAFE_ALLOCA;
+
   /* In order to build the menus, we need to call the keymap
      accessors.  They all call QUIT.  But this function is called
      during redisplay, during which a quit is fatal.  So inhibit
@@ -7467,7 +7474,7 @@
 	&& !NILP (Voverriding_local_map))
       {
 	/* Yes, use them (if non-nil) as well as the global map.  */
-	maps = alloca (3 * sizeof (maps[0]));
+	maps = mapsbuf;
 	nmaps = 0;
 	if (!NILP (KVAR (current_kboard, Voverriding_terminal_local_map)))
 	  maps[nmaps++] = KVAR (current_kboard, Voverriding_terminal_local_map);
@@ -7484,7 +7491,7 @@
 	Lisp_Object tem;
 	ptrdiff_t nminor;
 	nminor = current_minor_maps (NULL, &tmaps);
-	maps = alloca ((nminor + 4) * sizeof *maps);
+	SAFE_NALLOCA (maps, 1, nminor + 4);
 	nmaps = 0;
 	tem = KVAR (current_kboard, Voverriding_terminal_local_map);
 	if (!NILP (tem) && !NILP (Voverriding_local_map_menu_flag))
@@ -7556,6 +7563,7 @@
   }
 
   Vinhibit_quit = oquit;
+  SAFE_FREE ();
   return menu_bar_items_vector;
 }
 \f
@@ -7992,9 +8000,11 @@
 tool_bar_items (Lisp_Object reuse, int *nitems)
 {
   Lisp_Object *maps;
+  Lisp_Object mapsbuf[3];
   ptrdiff_t nmaps, i;
   Lisp_Object oquit;
   Lisp_Object *tmaps;
+  USE_SAFE_ALLOCA;
 
   *nitems = 0;
 
@@ -8018,7 +8028,7 @@
       && !NILP (Voverriding_local_map))
     {
       /* Yes, use them (if non-nil) as well as the global map.  */
-      maps = alloca (3 * sizeof *maps);
+      maps = mapsbuf;
       nmaps = 0;
       if (!NILP (KVAR (current_kboard, Voverriding_terminal_local_map)))
 	maps[nmaps++] = KVAR (current_kboard, Voverriding_terminal_local_map);
@@ -8035,7 +8045,7 @@
       Lisp_Object tem;
       ptrdiff_t nminor;
       nminor = current_minor_maps (NULL, &tmaps);
-      maps = alloca ((nminor + 4) * sizeof *maps);
+      SAFE_NALLOCA (maps, 1, nminor + 4);
       nmaps = 0;
       tem = KVAR (current_kboard, Voverriding_terminal_local_map);
       if (!NILP (tem) && !NILP (Voverriding_local_map_menu_flag))
@@ -8064,6 +8074,7 @@
 
   Vinhibit_quit = oquit;
   *nitems = ntool_bar_items / TOOL_BAR_ITEM_NSLOTS;
+  SAFE_FREE ();
   return tool_bar_items_vector;
 }
 

=== modified file 'src/keymap.c'
--- src/keymap.c	2014-07-14 04:44:01 +0000
+++ src/keymap.c	2014-09-05 06:03:28 +0000
@@ -2883,13 +2883,14 @@
 	  if (!SYMBOLP (modes[i]))
 	    emacs_abort ();
 
-	  p = title = alloca (42 + SCHARS (SYMBOL_NAME (modes[i])));
+	  USE_SAFE_ALLOCA;
+	  p = title = SAFE_ALLOCA (42 + SBYTES (SYMBOL_NAME (modes[i])));
 	  *p++ = '\f';
 	  *p++ = '\n';
 	  *p++ = '`';
 	  memcpy (p, SDATA (SYMBOL_NAME (modes[i])),
-		  SCHARS (SYMBOL_NAME (modes[i])));
-	  p += SCHARS (SYMBOL_NAME (modes[i]));
+		  SBYTES (SYMBOL_NAME (modes[i])));
+	  p += SBYTES (SYMBOL_NAME (modes[i]));
 	  *p++ = '\'';
 	  memcpy (p, " Minor Mode Bindings", strlen (" Minor Mode Bindings"));
 	  p += strlen (" Minor Mode Bindings");
@@ -2898,6 +2899,7 @@
 	  describe_map_tree (maps[i], 1, shadow, prefix,
 			     title, nomenu, 0, 0, 0);
 	  shadow = Fcons (maps[i], shadow);
+	  SAFE_FREE ();
 	}
 
       start1 = get_local_map (BUF_PT (XBUFFER (buffer)),
@@ -3184,10 +3186,10 @@
 
   /* These accumulate the values from sparse keymap bindings,
      so we can sort them and handle them in order.  */
-  int length_needed = 0;
+  ptrdiff_t length_needed = 0;
   struct describe_map_elt *vect;
-  int slots_used = 0;
-  int i;
+  ptrdiff_t slots_used = 0;
+  ptrdiff_t i;
 
   suppress = Qnil;
 
@@ -3207,7 +3209,8 @@
   for (tail = map; CONSP (tail); tail = XCDR (tail))
     length_needed++;
 
-  vect = alloca (length_needed * sizeof *vect);
+  USE_SAFE_ALLOCA;
+  SAFE_NALLOCA (vect, 1, length_needed);
 
   for (tail = map; CONSP (tail); tail = XCDR (tail))
     {
@@ -3350,6 +3353,7 @@
 	}
     }
 
+  SAFE_FREE ();
   UNGCPRO;
 }
 

=== modified file 'src/lisp.h'
--- src/lisp.h	2014-09-02 18:05:00 +0000
+++ src/lisp.h	2014-09-05 06:03:28 +0000
@@ -4451,12 +4451,6 @@
   return egetenv_internal (var, strlen (var));
 }
 
-/* Copy Lisp string to temporary (allocated on stack) C string.  */
-
-#define xlispstrdupa(string)			\
-  memcpy (alloca (SBYTES (string) + 1),		\
-	  SSDATA (string), SBYTES (string) + 1)
-
 /* Set up the name of the machine we're running on.  */
 extern void init_system_name (void);
 
@@ -4484,7 +4478,7 @@
 
 /* SAFE_ALLOCA allocates a simple buffer.  */
 
-#define SAFE_ALLOCA(size) ((size) < MAX_ALLOCA	\
+#define SAFE_ALLOCA(size) ((size) <= MAX_ALLOCA	\
 			   ? alloca (size)	\
 			   : (sa_must_free = true, record_xmalloc (size)))
 
@@ -4504,6 +4498,14 @@
       }								 \
   } while (false)
 
+/* SAFE_ALLOCA_STRING allocates a C copy of a Lisp string.  */
+
+#define SAFE_ALLOCA_STRING(ptr, string)			\
+  do {							\
+    (ptr) = SAFE_ALLOCA (SBYTES (string) + 1);		\
+    memcpy (ptr, SDATA (string), SBYTES (string) + 1);	\
+  } while (false)
+
 /* SAFE_FREE frees xmalloced memory and enables GC as needed.  */
 
 #define SAFE_FREE()			\
@@ -4519,9 +4521,9 @@
 
 #define SAFE_ALLOCA_LISP(buf, nelt)			       \
   do {							       \
-    if ((nelt) < MAX_ALLOCA / word_size)		       \
+    if ((nelt) <= MAX_ALLOCA / word_size)		       \
       (buf) = alloca ((nelt) * word_size);		       \
-    else if ((nelt) < min (PTRDIFF_MAX, SIZE_MAX) / word_size) \
+    else if ((nelt) <= min (PTRDIFF_MAX, SIZE_MAX) / word_size) \
       {							       \
 	Lisp_Object arg_;				       \
 	(buf) = xmalloc ((nelt) * word_size);		       \

=== modified file 'src/lread.c'
--- src/lread.c	2014-09-01 16:05:43 +0000
+++ src/lread.c	2014-09-05 06:03:28 +0000
@@ -1473,6 +1473,7 @@
   ptrdiff_t max_suffix_len = 0;
   int last_errno = ENOENT;
   int save_fd = -1;
+  USE_SAFE_ALLOCA;
 
   /* The last-modified time of the newest matching file found.
      Initialize it to something less than all valid timestamps.  */
@@ -1513,7 +1514,10 @@
 	 this path element/specified file name and any possible suffix.  */
       want_length = max_suffix_len + SBYTES (filename);
       if (fn_size <= want_length)
-	fn = alloca (fn_size = 100 + want_length);
+	{
+	  fn_size = 100 + want_length;
+	  fn = SAFE_ALLOCA (fn_size);
+	}
 
       /* Loop over suffixes.  */
       for (tail = NILP (suffixes) ? list1 (empty_unibyte_string) : suffixes;
@@ -1579,6 +1583,7 @@
                   /* We succeeded; return this descriptor and filename.  */
                   if (storeptr)
                     *storeptr = string;
+		  SAFE_FREE ();
                   UNGCPRO;
                   return -2;
 		}
@@ -1651,6 +1656,7 @@
                       /* We succeeded; return this descriptor and filename.  */
                       if (storeptr)
                         *storeptr = string;
+		      SAFE_FREE ();
                       UNGCPRO;
                       return fd;
                     }
@@ -1661,6 +1667,7 @@
                 {
                   if (storeptr)
                     *storeptr = save_string;
+		  SAFE_FREE ();
                   UNGCPRO;
                   return save_fd;
                 }
@@ -1670,6 +1677,7 @@
 	break;
     }
 
+  SAFE_FREE ();
   UNGCPRO;
   errno = last_errno;
   return -1;

=== modified file 'src/menu.c'
--- src/menu.c	2014-08-10 08:26:28 +0000
+++ src/menu.c	2014-09-05 06:03:28 +0000
@@ -632,8 +632,9 @@
   widget_value **submenu_stack;
   bool panes_seen = 0;
   struct frame *f = XFRAME (Vmenu_updating_frame);
+  USE_SAFE_ALLOCA;
 
-  submenu_stack = alloca (menu_items_used * sizeof *submenu_stack);
+  SAFE_NALLOCA (submenu_stack, 1, menu_items_used);
   wv = make_widget_value ("menu", NULL, true, Qnil);
   wv->button_type = BUTTON_TYPE_NONE;
   first_wv = wv;
@@ -835,11 +836,12 @@
      that was originally a button, return it by itself.  */
   if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
     {
-      wv = first_wv->contents;
-      xfree (first_wv);
-      return wv;
+      wv = first_wv;
+      first_wv = first_wv->contents;
+      xfree (wv);
     }
 
+  SAFE_FREE ();
   return first_wv;
 }
 
@@ -890,9 +892,10 @@
   Lisp_Object *subprefix_stack;
   int submenu_depth = 0;
   int i;
+  USE_SAFE_ALLOCA;
 
   entry = Qnil;
-  subprefix_stack = alloca (menu_bar_items_used * sizeof *subprefix_stack);
+  SAFE_NALLOCA (subprefix_stack, 1, menu_bar_items_used);
   prefix = Qnil;
   i = 0;
 
@@ -954,11 +957,13 @@
 	      buf.arg = entry;
 	      kbd_buffer_store_event (&buf);
 
-	      return;
+	      break;
 	    }
 	  i += MENU_ITEMS_ITEM_LENGTH;
 	}
     }
+
+  SAFE_FREE ();
 }
 
 #endif /* USE_X_TOOLKIT || USE_GTK || HAVE_NS || HAVE_NTGUI */
@@ -973,10 +978,11 @@
   int i;
   Lisp_Object *subprefix_stack;
   int submenu_depth = 0;
+  USE_SAFE_ALLOCA;
 
   prefix = entry = Qnil;
   i = 0;
-  subprefix_stack = alloca (menu_items_used * word_size);
+  SAFE_ALLOCA_LISP (subprefix_stack, menu_items_used);
 
   while (i < menu_items_used)
     {
@@ -1018,11 +1024,13 @@
                     if (!NILP (subprefix_stack[j]))
                       entry = Fcons (subprefix_stack[j], entry);
                 }
+	      SAFE_FREE ();
               return entry;
             }
           i += MENU_ITEMS_ITEM_LENGTH;
         }
     }
+  SAFE_FREE ();
   return Qnil;
 }
 #endif  /* HAVE_NS */

=== modified file 'src/print.c'
--- src/print.c	2014-07-17 09:12:51 +0000
+++ src/print.c	2014-09-05 06:03:28 +0000
@@ -169,11 +169,13 @@
        if (print_buffer_pos != print_buffer_pos_byte			\
 	   && NILP (BVAR (current_buffer, enable_multibyte_characters)))\
 	 {								\
-	   unsigned char *temp = alloca (print_buffer_pos + 1);		\
+	   USE_SAFE_ALLOCA;						\
+	   unsigned char *temp = SAFE_ALLOCA (print_buffer_pos + 1);	\
 	   copy_text ((unsigned char *) print_buffer, temp,		\
 		      print_buffer_pos_byte, 1, 0);			\
 	   insert_1_both ((char *) temp, print_buffer_pos,		\
 			  print_buffer_pos, 0, 1, 0);			\
+	   SAFE_FREE ();						\
 	 }								\
        else								\
 	 insert_1_both (print_buffer, print_buffer_pos,			\

=== modified file 'src/process.c'
--- src/process.c	2014-08-09 16:20:29 +0000
+++ src/process.c	2014-09-05 06:03:28 +0000
@@ -1386,9 +1386,10 @@
   (ptrdiff_t nargs, Lisp_Object *args)
 {
   Lisp_Object buffer, name, program, proc, current_dir, tem;
-  register unsigned char **new_argv;
+  unsigned char **new_argv;
   ptrdiff_t i;
   ptrdiff_t count = SPECPDL_INDEX ();
+  USE_SAFE_ALLOCA;
 
   buffer = args[1];
   if (!NILP (buffer))
@@ -1464,7 +1465,7 @@
     val = Vcoding_system_for_read;
     if (NILP (val))
       {
-	args2 = alloca ((nargs + 1) * sizeof *args2);
+	SAFE_ALLOCA_LISP (args2, nargs + 1);
 	args2[0] = Qstart_process;
 	for (i = 0; i < nargs; i++) args2[i + 1] = args[i];
 	GCPRO2 (proc, current_dir);
@@ -1483,7 +1484,7 @@
       {
 	if (EQ (coding_systems, Qt))
 	  {
-	    args2 = alloca ((nargs + 1) * sizeof *args2);
+	    SAFE_ALLOCA_LISP (args2, nargs + 1);
 	    args2[0] = Qstart_process;
 	    for (i = 0; i < nargs; i++) args2[i + 1] = args[i];
 	    GCPRO2 (proc, current_dir);
@@ -1578,7 +1579,7 @@
 
       /* Now that everything is encoded we can collect the strings into
 	 NEW_ARGV.  */
-      new_argv = alloca ((nargs - 1) * sizeof *new_argv);
+      SAFE_NALLOCA (new_argv, 1, nargs - 1);
       new_argv[nargs - 2] = 0;
 
       for (i = nargs - 2; i-- != 0; )
@@ -1592,6 +1593,7 @@
   else
     create_pty (proc);
 
+  SAFE_FREE ();
   return unbind_to (count, proc);
 }
 
@@ -2071,8 +2073,10 @@
 	   && VECTORP (XCDR (address)))
     {
       struct sockaddr *sa;
+      p = XVECTOR (XCDR (address));
+      if (MAX_ALLOCA - sizeof sa->sa_family < p->header.size)
+	return 0;
       *familyp = XINT (XCAR (address));
-      p = XVECTOR (XCDR (address));
       return p->header.size + sizeof (sa->sa_family);
     }
   return 0;
@@ -4973,18 +4977,17 @@
    for decoding.  */
 
 static int
-read_process_output (Lisp_Object proc, register int channel)
+read_process_output (Lisp_Object proc, int channel)
 {
-  register ssize_t nbytes;
-  char *chars;
-  register struct Lisp_Process *p = XPROCESS (proc);
+  ssize_t nbytes;
+  struct Lisp_Process *p = XPROCESS (proc);
   struct coding_system *coding = proc_decode_coding_system[channel];
   int carryover = p->decoding_carryover;
-  int readmax = 4096;
+  enum { readmax = 4096 };
   ptrdiff_t count = SPECPDL_INDEX ();
   Lisp_Object odeactivate;
+  char chars[sizeof coding->carryover + readmax];
 
-  chars = alloca (carryover + readmax);
   if (carryover)
     /* See the comment above.  */
     memcpy (chars, SDATA (p->decoding_buf), carryover);
@@ -6837,7 +6840,7 @@
 {
   FD_SET (fd, &input_wait_mask);
   FD_SET (fd, &non_keyboard_wait_mask);
-  FD_SET (fd, &non_process_wait_mask);
+  FD_SET (fd, &non_process_wait_mask);
   fd_callback_info[fd].func = timerfd_callback;
   fd_callback_info[fd].data = NULL;
   fd_callback_info[fd].condition |= FOR_READ;

=== modified file 'src/regex.c'
--- src/regex.c	2014-07-15 14:04:06 +0000
+++ src/regex.c	2014-09-05 06:03:28 +0000
@@ -457,11 +457,17 @@
 
 # endif /* not alloca */
 
-# define REGEX_ALLOCATE alloca
+# ifdef emacs
+#  define REGEX_USE_SAFE_ALLOCA USE_SAFE_ALLOCA
+#  define REGEX_SAFE_FREE() SAFE_FREE ()
+#  define REGEX_ALLOCATE SAFE_ALLOCA
+# else
+#  define REGEX_ALLOCATE alloca
+# endif
 
 /* Assumes a `char *destination' variable.  */
 # define REGEX_REALLOCATE(source, osize, nsize)				\
-  (destination = alloca (nsize),					\
+  (destination = REGEX_ALLOCATE (nsize),				\
    memcpy (destination, source, osize))
 
 /* No need to do anything to free, after alloca.  */
@@ -469,6 +475,11 @@
 
 #endif /* not REGEX_MALLOC */
 
+#ifndef REGEX_USE_SAFE_ALLOCA
+# define REGEX_USE_SAFE_ALLOCA ((void) 0)
+# define REGEX_SAFE_FREE() ((void) 0)
+#endif
+
 /* Define how to allocate the failure stack.  */
 
 #if defined REL_ALLOC && defined REGEX_MALLOC
@@ -482,22 +493,10 @@
 
 #else /* not using relocating allocator */
 
-# ifdef REGEX_MALLOC
-
-#  define REGEX_ALLOCATE_STACK malloc
-#  define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize)
-#  define REGEX_FREE_STACK free
-
-# else /* not REGEX_MALLOC */
-
-#  define REGEX_ALLOCATE_STACK alloca
-
-#  define REGEX_REALLOCATE_STACK(source, osize, nsize)			\
-   REGEX_REALLOCATE (source, osize, nsize)
-/* No need to explicitly free anything.  */
-#  define REGEX_FREE_STACK(arg) ((void)0)
-
-# endif /* not REGEX_MALLOC */
+# define REGEX_ALLOCATE_STACK(size) REGEX_ALLOCATE (size)
+# define REGEX_REALLOCATE_STACK(source, o, n) REGEX_REALLOCATE (source, o, n)
+# define REGEX_FREE_STACK(ptr) REGEX_FREE (ptr)
+
 #endif /* not using relocating allocator */
 
 
@@ -4579,6 +4578,7 @@
     FREE_VAR (regend);							\
     FREE_VAR (best_regstart);						\
     FREE_VAR (best_regend);						\
+    REGEX_SAFE_FREE ();							\
   } while (0)
 #else
 # define FREE_VARIABLES() ((void)0) /* Do nothing!  But inhibit gcc warning.  */
@@ -5018,6 +5018,8 @@
 
   DEBUG_PRINT ("\n\nEntering re_match_2.\n");
 
+  REGEX_USE_SAFE_ALLOCA;
+
   INIT_FAIL_STACK ();
 
 #ifdef MATCH_MAY_ALLOCATE

=== modified file 'src/scroll.c'
--- src/scroll.c	2014-08-03 12:34:44 +0000
+++ src/scroll.c	2014-09-05 06:03:28 +0000
@@ -245,18 +245,20 @@
 {
   struct matrix_elt *p;
   int i, j, k;
+  USE_SAFE_ALLOCA;
 
   /* True if we have set a terminal window with set_terminal_window.  */
   bool terminal_window_p = 0;
 
   /* A queue for line insertions to be done.  */
   struct queue { int count, pos; };
-  struct queue *queue_start
-    = alloca (current_matrix->nrows * sizeof *queue_start);
+  struct queue *queue_start;
+  SAFE_NALLOCA (queue_start, 1, current_matrix->nrows);
   struct queue *queue = queue_start;
 
-  char *retained_p = alloca (window_size * sizeof *retained_p);
-  int *copy_from = alloca (window_size * sizeof *copy_from);
+  char *retained_p = SAFE_ALLOCA (window_size);
+  int *copy_from;
+  SAFE_NALLOCA (copy_from, 1, window_size);
 
   /* Zero means line is empty.  */
   memset (retained_p, 0, window_size * sizeof (char));
@@ -378,6 +380,7 @@
 
   if (terminal_window_p)
     set_terminal_window (frame, 0);
+  SAFE_FREE ();
 }
 
 \f
@@ -649,10 +652,12 @@
 {
   struct matrix_elt *p;
   int i, j;
+  USE_SAFE_ALLOCA;
 
   /* A queue of deletions and insertions to be performed.  */
   struct alt_queue { int count, pos, window; };
-  struct alt_queue *queue_start = alloca (window_size * sizeof *queue_start);
+  struct alt_queue *queue_start;
+  SAFE_NALLOCA (queue_start, 1, window_size);
   struct alt_queue *queue = queue_start;
 
   /* True if a terminal window has been set with set_terminal_window.  */
@@ -667,11 +672,12 @@
   bool write_follows_p = 1;
 
   /* For each row in the new matrix what row of the old matrix it is.  */
-  int *copy_from = alloca (window_size * sizeof *copy_from);
+  int *copy_from;
+  SAFE_NALLOCA (copy_from, 1, window_size);
 
   /* Non-zero for each row in the new matrix that is retained from the
      old matrix.  Lines not retained are empty.  */
-  char *retained_p = alloca (window_size * sizeof *retained_p);
+  char *retained_p = SAFE_ALLOCA (window_size);
 
   memset (retained_p, 0, window_size * sizeof (char));
 
@@ -787,6 +793,7 @@
 
   if (terminal_window_p)
     set_terminal_window (frame, 0);
+  SAFE_FREE ();
 }
 
 
@@ -796,8 +803,9 @@
 	     int unchanged_at_bottom, int *draw_cost, int *old_draw_cost,
 	     unsigned *old_hash, unsigned *new_hash, int free_at_end)
 {
-  struct matrix_elt *matrix
-    = alloca ((window_size + 1) * (window_size + 1) * sizeof *matrix);
+  USE_SAFE_ALLOCA;
+  struct matrix_elt *matrix;
+  SAFE_NALLOCA (matrix, window_size + 1, window_size + 1);
 
   if (FRAME_SCROLL_REGION_OK (frame))
     {
@@ -817,6 +825,8 @@
                     frame->current_matrix, matrix, window_size,
 		    unchanged_at_top);
     }
+
+  SAFE_FREE ();
 }
 
 

=== modified file 'src/search.c'
--- src/search.c	2014-06-23 04:11:29 +0000
+++ src/search.c	2014-09-05 06:03:28 +0000
@@ -1318,6 +1318,7 @@
 	 translation.  Otherwise set to zero later.  */
       int char_base = -1;
       bool boyer_moore_ok = 1;
+      USE_SAFE_ALLOCA;
 
       /* MULTIBYTE says whether the text to be searched is multibyte.
 	 We must convert PATTERN to match that, or we will not really
@@ -1335,7 +1336,7 @@
 	  raw_pattern_size_byte
 	    = count_size_as_multibyte (SDATA (string),
 				       raw_pattern_size);
-	  raw_pattern = alloca (raw_pattern_size_byte + 1);
+	  raw_pattern = SAFE_ALLOCA (raw_pattern_size_byte + 1);
 	  copy_text (SDATA (string), raw_pattern,
 		     SCHARS (string), 0, 1);
 	}
@@ -1349,7 +1350,7 @@
 	     the chosen single-byte character set can possibly match.  */
 	  raw_pattern_size = SCHARS (string);
 	  raw_pattern_size_byte = SCHARS (string);
-	  raw_pattern = alloca (raw_pattern_size + 1);
+	  raw_pattern = SAFE_ALLOCA (raw_pattern_size + 1);
 	  copy_text (SDATA (string), raw_pattern,
 		     SBYTES (string), 1, 0);
 	}
@@ -1357,7 +1358,7 @@
       /* Copy and optionally translate the pattern.  */
       len = raw_pattern_size;
       len_byte = raw_pattern_size_byte;
-      patbuf = alloca (len * MAX_MULTIBYTE_LENGTH);
+      SAFE_NALLOCA (patbuf, MAX_MULTIBYTE_LENGTH, len);
       pat = patbuf;
       base_pat = raw_pattern;
       if (multibyte)
@@ -1497,13 +1498,15 @@
       len_byte = pat - patbuf;
       pat = base_pat = patbuf;
 
-      if (boyer_moore_ok)
-	return boyer_moore (n, pat, len_byte, trt, inverse_trt,
-			    pos_byte, lim_byte,
-			    char_base);
-      else
-	return simple_search (n, pat, raw_pattern_size, len_byte, trt,
-			      pos, pos_byte, lim, lim_byte);
+      Lisp_Object result
+	= (boyer_moore_ok
+	   ? boyer_moore (n, pat, len_byte, trt, inverse_trt,
+			  pos_byte, lim_byte,
+			  char_base)
+	   : simple_search (n, pat, raw_pattern_size, len_byte, trt,
+			    pos, pos_byte, lim, lim_byte));
+      SAFE_FREE ();
+      return result;
     }
 }
 \f
@@ -2809,7 +2812,8 @@
 
   prev = Qnil;
 
-  data = alloca ((2 * search_regs.num_regs + 1) * sizeof *data);
+  USE_SAFE_ALLOCA;
+  SAFE_NALLOCA (data, 1, 2 * search_regs.num_regs + 1);
 
   len = 0;
   for (i = 0; i < search_regs.num_regs; i++)
@@ -2852,25 +2856,28 @@
 
   /* If REUSE is not usable, cons up the values and return them.  */
   if (! CONSP (reuse))
-    return Flist (len, data);
+    reuse = Flist (len, data);
+  else
+    {
+      /* If REUSE is a list, store as many value elements as will fit
+	 into the elements of REUSE.  */
+      for (i = 0, tail = reuse; CONSP (tail);
+	   i++, tail = XCDR (tail))
+	{
+	  if (i < len)
+	    XSETCAR (tail, data[i]);
+	  else
+	    XSETCAR (tail, Qnil);
+	  prev = tail;
+	}
 
-  /* If REUSE is a list, store as many value elements as will fit
-     into the elements of REUSE.  */
-  for (i = 0, tail = reuse; CONSP (tail);
-       i++, tail = XCDR (tail))
-    {
+      /* If we couldn't fit all value elements into REUSE,
+	 cons up the rest of them and add them to the end of REUSE.  */
       if (i < len)
-	XSETCAR (tail, data[i]);
-      else
-	XSETCAR (tail, Qnil);
-      prev = tail;
+	XSETCDR (prev, Flist (len - i, data + i));
     }
 
-  /* If we couldn't fit all value elements into REUSE,
-     cons up the rest of them and add them to the end of REUSE.  */
-  if (i < len)
-    XSETCDR (prev, Flist (len - i, data + i));
-
+  SAFE_FREE ();
   return reuse;
 }
 
@@ -3075,7 +3082,8 @@
 
   CHECK_STRING (string);
 
-  temp = alloca (SBYTES (string) * 2);
+  USE_SAFE_ALLOCA;
+  SAFE_NALLOCA (temp, 2, SBYTES (string));
 
   /* Now copy the data into the new string, inserting escapes. */
 
@@ -3093,10 +3101,13 @@
       *out++ = *in;
     }
 
-  return make_specified_string (temp,
-				SCHARS (string) + backslashes_added,
-				out - temp,
-				STRING_MULTIBYTE (string));
+  Lisp_Object result
+    = make_specified_string (temp,
+			     SCHARS (string) + backslashes_added,
+			     out - temp,
+			     STRING_MULTIBYTE (string));
+  SAFE_FREE ();
+  return result;
 }
 
 /* Like find_newline, but doesn't use the cache, and only searches forward.  */

=== modified file 'src/sound.c'
--- src/sound.c	2014-03-25 14:43:26 +0000
+++ src/sound.c	2014-09-05 06:03:28 +0000
@@ -564,12 +564,11 @@
 	       SBYTES (s->data) - sizeof *header);
   else
     {
-      char *buffer;
       ptrdiff_t nbytes = 0;
       ptrdiff_t blksize = sd->period_size ? sd->period_size (sd) : 2048;
       ptrdiff_t data_left = header->data_length;
-
-      buffer = alloca (blksize);
+      USE_SAFE_ALLOCA;
+      char *buffer = SAFE_ALLOCA (blksize);
       lseek (s->fd, sizeof *header, SEEK_SET);
       while (data_left > 0
              && (nbytes = emacs_read (s->fd, buffer, blksize)) > 0)
@@ -582,6 +581,7 @@
 
       if (nbytes < 0)
 	sound_perror ("Error reading sound file");
+      SAFE_FREE ();
     }
 }
 
@@ -656,19 +656,20 @@
   else
     {
       ptrdiff_t blksize = sd->period_size ? sd->period_size (sd) : 2048;
-      char *buffer;
       ptrdiff_t nbytes;
 
       /* Seek */
       lseek (s->fd, header->data_offset, SEEK_SET);
 
       /* Copy sound data to the device.  */
-      buffer = alloca (blksize);
+      USE_SAFE_ALLOCA;
+      char *buffer = SAFE_ALLOCA (blksize);
       while ((nbytes = emacs_read (s->fd, buffer, blksize)) > 0)
 	sd->write (sd, buffer, nbytes);
 
       if (nbytes < 0)
 	sound_perror ("Error reading sound file");
+      SAFE_FREE ();
     }
 }
 
@@ -1309,7 +1310,6 @@
   struct gcpro gcpro1, gcpro2;
   Lisp_Object args[2];
 #else /* WINDOWSNT */
-  int len = 0;
   Lisp_Object lo_file = {0};
   char * psz_file = NULL;
   unsigned long ui_volume_tmp = UINT_MAX;
@@ -1326,7 +1326,8 @@
   current_sound_device = xzalloc (sizeof *current_sound_device);
   current_sound = xzalloc (sizeof *current_sound);
   record_unwind_protect_void (sound_cleanup);
-  current_sound->header = alloca (MAX_SOUND_HEADER_BYTES);
+  char headerbuf[MAX_SOUND_HEADER_BYTES];
+  current_sound->header = headerbuf;
 
   if (STRINGP (attrs[SOUND_FILE]))
     {

=== modified file 'src/syntax.c'
--- src/syntax.c	2014-09-04 16:14:05 +0000
+++ src/syntax.c	2014-09-05 06:03:28 +0000
@@ -1567,6 +1567,7 @@
   const unsigned char *str;
   int len;
   Lisp_Object iso_classes;
+  USE_SAFE_ALLOCA;
 
   CHECK_STRING (string);
   iso_classes = Qnil;
@@ -1699,7 +1700,7 @@
 	  memcpy (himap, fastmap + 0200, 0200);
 	  himap[0200] = 0;
 	  memset (fastmap + 0200, 0, 0200);
-	  char_ranges = alloca (sizeof *char_ranges * 128 * 2);
+	  SAFE_NALLOCA (char_ranges, 2, 128);
 	  i = 0;
 
 	  while ((p1 = memchr (himap + i, 1, 0200 - i)))
@@ -1723,7 +1724,7 @@
     }
   else				/* STRING is multibyte */
     {
-      char_ranges = alloca (sizeof *char_ranges * SCHARS (string) * 2);
+      SAFE_NALLOCA (char_ranges, 2, SCHARS (string));
 
       while (i_byte < size_byte)
 	{
@@ -2032,6 +2033,7 @@
     SET_PT_BOTH (pos, pos_byte);
     immediate_quit = 0;
 
+    SAFE_FREE ();
     return make_number (PT - start_point);
   }
 }

=== modified file 'src/term.c'
--- src/term.c	2014-08-10 16:28:36 +0000
+++ src/term.c	2014-09-05 06:03:28 +0000
@@ -3191,6 +3191,7 @@
   Lisp_Object selectface;
   int first_item = 0;
   int col, row;
+  USE_SAFE_ALLOCA;
 
   /* Don't allow non-positive x0 and y0, lest the menu will wrap
      around the display.  */
@@ -3199,7 +3200,7 @@
   if (y0 <= 0)
     y0 = 1;
 
-  state = alloca (menu->panecount * sizeof (struct tty_menu_state));
+  SAFE_NALLOCA (state, 1, menu->panecount);
   memset (state, 0, sizeof (*state));
   faces[0]
     = lookup_derived_face (sf, intern ("tty-menu-disabled-face"),
@@ -3421,6 +3422,7 @@
   discard_mouse_events ();
   if (!kbd_buffer_events_waiting ())
     clear_input_pending ();
+  SAFE_FREE ();
   return result;
 }
 
@@ -3606,6 +3608,7 @@
   item_y = y += f->top_pos;
 
   /* Create all the necessary panes and their items.  */
+  USE_SAFE_ALLOCA;
   maxwidth = maxlines = lines = i = 0;
   lpane = TTYM_FAILURE;
   while (i < menu_items_used)
@@ -3674,9 +3677,7 @@
 
 	  if (!NILP (descrip))
 	    {
-	      /* If alloca is fast, use that to make the space,
-		 to reduce gc needs.  */
-	      item_data = (char *) alloca (maxwidth + SBYTES (descrip) + 1);
+	      item_data = SAFE_ALLOCA (maxwidth + SBYTES (descrip) + 1);
 	      memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
 	      for (j = SCHARS (item_name); j < maxwidth; j++)
 		item_data[j] = ' ';
@@ -3829,6 +3830,7 @@
 
  tty_menu_end:
 
+  SAFE_FREE ();
   unbind_to (specpdl_count, Qnil);
   return entry;
 }

=== modified file 'src/textprop.c'
--- src/textprop.c	2014-01-14 17:59:19 +0000
+++ src/textprop.c	2014-09-05 06:03:28 +0000
@@ -660,6 +660,7 @@
 
       set_buffer_temp (XBUFFER (object));
 
+      USE_SAFE_ALLOCA;
       GET_OVERLAYS_AT (XINT (position), overlay_vec, noverlays, NULL, 0);
       noverlays = sort_overlays (overlay_vec, noverlays, w);
 
@@ -674,9 +675,11 @@
 	      if (overlay)
 		/* Return the overlay we got the property from.  */
 		*overlay = overlay_vec[noverlays];
+	      SAFE_FREE ();
 	      return tem;
 	    }
 	}
+      SAFE_FREE ();
     }
 
   if (overlay)

=== modified file 'src/window.c'
--- src/window.c	2014-08-11 00:59:34 +0000
+++ src/window.c	2014-09-05 06:03:28 +0000
@@ -6124,6 +6124,7 @@
   Lisp_Object frame;
   struct frame *f;
   ptrdiff_t old_point = -1;
+  USE_SAFE_ALLOCA;
 
   CHECK_WINDOW_CONFIGURATION (configuration);
 
@@ -6231,8 +6232,8 @@
 	 really like to do is to free only those matrices not reused
 	 below.  */
       root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
-      leaf_windows = alloca (count_windows (root_window)
-			     * sizeof *leaf_windows);
+      int nwindows = count_windows (root_window);
+      SAFE_NALLOCA (leaf_windows, 1, nwindows);
       n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
 
       /* Kludge Alert!
@@ -6456,6 +6457,7 @@
   Vminibuf_scroll_window = data->minibuf_scroll_window;
   minibuf_selected_window = data->minibuf_selected_window;
 
+  SAFE_FREE ();
   return (FRAME_LIVE_P (f) ? Qt : Qnil);
 }
 

=== modified file 'src/xdisp.c'
--- src/xdisp.c	2014-09-04 16:14:05 +0000
+++ src/xdisp.c	2014-09-05 06:03:28 +0000
@@ -2626,15 +2626,14 @@
     {
       ptrdiff_t i;
       ptrdiff_t count = SPECPDL_INDEX ();
-      struct gcpro gcpro1;
-      Lisp_Object *args = alloca (nargs * word_size);
+      Lisp_Object *args;
+      USE_SAFE_ALLOCA;
+      SAFE_ALLOCA_LISP (args, nargs);
 
       args[0] = func;
       for (i = 1; i < nargs; i++)
 	args[i] = va_arg (ap, Lisp_Object);
 
-      GCPRO1 (args[0]);
-      gcpro1.nvars = nargs;
       specbind (Qinhibit_redisplay, Qt);
       if (inhibit_quit)
 	specbind (Qinhibit_quit, Qt);
@@ -2642,7 +2641,7 @@
 	 so there is no possibility of wanting to redisplay.  */
       val = internal_condition_case_n (Ffuncall, nargs, args, Qt,
 				       safe_eval_handler);
-      UNGCPRO;
+      SAFE_FREE ();
       val = unbind_to (count, val);
     }
 
@@ -3659,6 +3658,7 @@
   ptrdiff_t i, noverlays;
   ptrdiff_t endpos;
   Lisp_Object *overlays;
+  USE_SAFE_ALLOCA;
 
   /* Get all overlays at the given position.  */
   GET_OVERLAYS_AT (pos, overlays, noverlays, &endpos, 1);
@@ -3675,6 +3675,7 @@
       endpos = min (endpos, oendpos);
     }
 
+  SAFE_FREE ();
   return endpos;
 }
 
@@ -5735,10 +5736,11 @@
   Lisp_Object overlay, window, str, invisible;
   struct Lisp_Overlay *ov;
   ptrdiff_t start, end;
-  ptrdiff_t size = 20;
   ptrdiff_t n = 0, i, j;
   int invis_p;
-  struct overlay_entry *entries = alloca (size * sizeof *entries);
+  struct overlay_entry entriesbuf[20];
+  ptrdiff_t size = ARRAYELTS (entriesbuf);
+  struct overlay_entry *entries = entriesbuf;
   USE_SAFE_ALLOCA;
 
   if (charpos <= 0)
@@ -10191,9 +10193,9 @@
     {
       ptrdiff_t nbytes = SBYTES (m);
       bool multibyte = STRING_MULTIBYTE (m);
+      char *buffer;
       USE_SAFE_ALLOCA;
-      char *buffer = SAFE_ALLOCA (nbytes);
-      memcpy (buffer, SDATA (m), nbytes);
+      SAFE_ALLOCA_STRING (buffer, m);
       message_dolog (buffer, nbytes, 1, multibyte);
       SAFE_FREE ();
     }
@@ -10395,11 +10397,13 @@
 	    {
 	      ptrdiff_t len;
 	      ptrdiff_t maxsize = FRAME_MESSAGE_BUF_SIZE (f);
-	      char *message_buf = alloca (maxsize + 1);
+	      USE_SAFE_ALLOCA;
+	      char *message_buf = SAFE_ALLOCA (maxsize + 1);
 
 	      len = doprnt (message_buf, maxsize, m, 0, ap);
 
 	      message3 (make_string (message_buf, len));
+	      SAFE_FREE ();
 	    }
 	  else
 	    message1 (0);
@@ -18695,10 +18699,10 @@
   else if (glyphs == 1)
     {
       int area;
+      char s[SHRT_MAX + 4];
 
       for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
 	{
-	  char *s = alloca (row->used[area] + 4);
 	  int i;
 
 	  for (i = 0; i < row->used[area]; ++i)
@@ -22690,10 +22694,8 @@
 	}
       else if (CHARACTERP (eoltype))
 	{
-	  unsigned char *tmp = alloca (MAX_MULTIBYTE_LENGTH);
 	  int c = XFASTINT (eoltype);
-	  eol_str_len = CHAR_STRING (c, tmp);
-	  eol_str = tmp;
+	  return buf + CHAR_STRING (c, (unsigned char *) buf);
 	}
       else
 	{
@@ -24609,7 +24611,7 @@
 	 face_id = (row)->glyphs[area][START].face_id;			   \
 									   \
 	 s = alloca (sizeof *s);					   \
-	 char2b = alloca ((END - START) * sizeof *char2b);		   \
+	 SAFE_NALLOCA (char2b, 1, (END) - (START));			   \
 	 INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL);	   \
 	 append_glyph_string (&HEAD, &TAIL, s);				   \
 	 s->x = (X);							   \
@@ -24637,7 +24639,7 @@
     struct glyph_string *first_s = NULL;				    \
     int n;								    \
     									    \
-    char2b = alloca (cmp->glyph_len * sizeof *char2b);			    \
+    SAFE_NALLOCA (char2b, 1, cmp->glyph_len);				    \
     									    \
     /* Make glyph_strings for each glyph sequence that is drawable by	    \
        the same face, and append them to HEAD/TAIL.  */			    \
@@ -24672,7 +24674,7 @@
     gstring = (composition_gstring_from_id				  \
 	       ((row)->glyphs[area][START].u.cmp.id));			  \
     s = alloca (sizeof *s);						  \
-    char2b = alloca (LGSTRING_GLYPH_LEN (gstring) * sizeof *char2b);	  \
+    SAFE_NALLOCA (char2b, 1, LGSTRING_GLYPH_LEN (gstring));		  \
     INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL);		  \
     append_glyph_string (&(HEAD), &(TAIL), s);				  \
     s->x = (X);								  \
@@ -24824,6 +24826,7 @@
      BUILD_GLYPH_STRINGS will modify its start parameter.  That's
      the reason we use a separate variable `i'.  */
   i = start;
+  USE_SAFE_ALLOCA;
   BUILD_GLYPH_STRINGS (i, end, head, tail, hl, x, last_x);
   if (tail)
     x_reached = tail->x + tail->background_width;
@@ -25023,6 +25026,7 @@
 
   RELEASE_HDC (hdc, f);
 
+  SAFE_FREE ();
   return x_reached;
 }
 
@@ -29291,6 +29295,8 @@
       /* Is this char mouse-active or does it have help-echo?  */
       position = make_number (pos);
 
+      USE_SAFE_ALLOCA;
+
       if (BUFFERP (object))
 	{
 	  /* Put all the overlays we want in a vector in overlay_vec.  */
@@ -29572,6 +29578,7 @@
       BEGV = obegv;
       ZV = ozv;
       current_buffer = obuf;
+      SAFE_FREE ();
     }
 
  set_cursor:

=== modified file 'src/xfaces.c'
--- src/xfaces.c	2014-08-07 10:15:52 +0000
+++ src/xfaces.c	2014-09-05 06:03:28 +0000
@@ -5980,6 +5980,7 @@
     endpos = XINT (end);
 
   /* Look at properties from overlays.  */
+  USE_SAFE_ALLOCA;
   {
     ptrdiff_t next_overlay;
 
@@ -6006,7 +6007,10 @@
   /* Optimize common cases where we can use the default face.  */
   if (noverlays == 0
       && NILP (prop))
-    return default_face->id;
+    {
+      SAFE_FREE ();
+      return default_face->id;
+    }
 
   /* Begin with attributes from the default face.  */
   memcpy (attrs, default_face->lface, sizeof attrs);
@@ -6034,6 +6038,8 @@
 
   *endptr = endpos;
 
+  SAFE_FREE ();
+
   /* Look up a realized face with the given face attributes,
      or realize a new one for ASCII characters.  */
   return lookup_face (f, attrs);

=== modified file 'src/xmenu.c'
--- src/xmenu.c	2014-07-27 13:21:30 +0000
+++ src/xmenu.c	2014-09-05 06:03:28 +0000
@@ -2023,7 +2023,8 @@
   Window root;
   XMenu *menu;
   int pane, selidx, lpane, status;
-  Lisp_Object entry, pane_prefix;
+  Lisp_Object entry = Qnil;
+  Lisp_Object pane_prefix;
   char *datap;
   int ulx, uly, width, height;
   int dispwidth, dispheight;
@@ -2045,6 +2046,7 @@
       return Qnil;
     }
 
+  USE_SAFE_ALLOCA;
   block_input ();
 
   /* Figure out which root window F is on.  */
@@ -2057,8 +2059,7 @@
   if (menu == NULL)
     {
       *error_name = "Can't create menu";
-      unblock_input ();
-      return Qnil;
+      goto return_entry;
     }
 
   /* Don't GC while we prepare and show the menu,
@@ -2101,8 +2102,7 @@
 	    {
 	      XMenuDestroy (FRAME_X_DISPLAY (f), menu);
 	      *error_name = "Can't create pane";
-	      unblock_input ();
-	      return Qnil;
+	      goto return_entry;
 	    }
 	  i += MENU_ITEMS_PANE_LENGTH;
 
@@ -2146,9 +2146,7 @@
 
 	  if (!NILP (descrip))
 	    {
-	      /* if alloca is fast, use that to make the space,
-		 to reduce gc needs.  */
-	      item_data = alloca (maxwidth + SBYTES (descrip) + 1);
+	      item_data = SAFE_ALLOCA (maxwidth + SBYTES (descrip) + 1);
 	      memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
 	      for (j = SCHARS (item_name); j < maxwidth; j++)
 		item_data[j] = ' ';
@@ -2166,8 +2164,7 @@
 	    {
 	      XMenuDestroy (FRAME_X_DISPLAY (f), menu);
 	      *error_name = "Can't add selection to menu";
-	      unblock_input ();
-	      return Qnil;
+	      goto return_entry;
 	    }
 	  i += MENU_ITEMS_ITEM_LENGTH;
           lines++;
@@ -2241,7 +2238,7 @@
   status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
                           x, y, ButtonReleaseMask, &datap,
                           menu_help_callback);
-  entry = pane_prefix = Qnil;
+  pane_prefix = Qnil;
 
   switch (status)
     {
@@ -2300,10 +2297,10 @@
       break;
     }
 
+ return_entry:
   unblock_input ();
-  unbind_to (specpdl_count, Qnil);
-
-  return entry;
+  SAFE_FREE ();
+  return unbind_to (specpdl_count, entry);
 }
 
 #endif /* not USE_X_TOOLKIT */


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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-05  6:08 bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation Paul Eggert
@ 2014-09-05  8:45 ` Dmitry Antipov
  2014-09-05 15:01   ` Paul Eggert
  2014-09-05 15:44   ` Stefan Monnier
  2014-09-05  8:59 ` Dmitry Antipov
  2014-09-07  7:20 ` Paul Eggert
  2 siblings, 2 replies; 23+ messages in thread
From: Dmitry Antipov @ 2014-09-05  8:45 UTC (permalink / raw
  To: Paul Eggert; +Cc: 18410

On 09/05/2014 10:08 AM, Paul Eggert wrote:

> Attached is a patch to fix the unbounded alloca calls that I found when auditing the Emacs source.
> I'm sending this to bug-gnu-emacs to give Eli a heads-up, as some of the fixes affect Windows code.
> This patch is relative to Emacs trunk bzr 117822.

Code like:

USE_SAFE_ALLOCA;                                                    |-
ptrdiff_t count = SPECPDL_INDEX ();                    |-           |
...                                                    | inner bind | outer bind
Lisp_Object result = unbind_to (count, Fsome_func ()); |-           |
SAFE_FREE ();                                                       |-
return result;

looks suboptimal because it calls unbind_to twice.  May be we need SAFE_FREE_RETURN,
somewhat similar to RETURN_UNGCPRO?  I.e. we should be able to say:

USE_SAFE_ALLOCA;
ptrdiff_t count = SPECPDL_INDEX ();
...
SAFE_FREE_RETURN (Fsome_func ());

Minor note: why specbind can't return previous binding level?
To avoid extra typing, someone can write:

ptrdiff_t count = specbind (Qsome_var, Qnil);

instead of:

ptrdiff_t count = SPECPDL_INDEX ();
specbind (Qsome_var, Qnil);

Dmitry






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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-05  6:08 bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation Paul Eggert
  2014-09-05  8:45 ` Dmitry Antipov
@ 2014-09-05  8:59 ` Dmitry Antipov
  2014-09-05 15:03   ` Paul Eggert
  2014-09-07  7:20 ` Paul Eggert
  2 siblings, 1 reply; 23+ messages in thread
From: Dmitry Antipov @ 2014-09-05  8:59 UTC (permalink / raw
  To: Paul Eggert; +Cc: 18410

On 09/05/2014 10:08 AM, Paul Eggert wrote:

> Attached is a patch to fix the unbounded alloca calls that I found when auditing the Emacs source.
> I'm sending this to bug-gnu-emacs to give Eli a heads-up, as some of the fixes affect Windows code.
> This patch is relative to Emacs trunk bzr 117822.

If __GNUC__, can't we use __attribute__ ((cleanup (freeing_function))) for implicit calls
to SAFE_FREE, similar to destructors in C++?

Dmitry






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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-05  8:45 ` Dmitry Antipov
@ 2014-09-05 15:01   ` Paul Eggert
  2014-09-05 15:44   ` Stefan Monnier
  1 sibling, 0 replies; 23+ messages in thread
From: Paul Eggert @ 2014-09-05 15:01 UTC (permalink / raw
  To: Dmitry Antipov; +Cc: 18410

Dmitry Antipov wrote:
> USE_SAFE_ALLOCA;                                                    |-
> ptrdiff_t count = SPECPDL_INDEX ();                    |-           |
> ...                                                    | inner bind |
> outer bind
> Lisp_Object result = unbind_to (count, Fsome_func ()); |-           |
> SAFE_FREE ();                                                       |-
> return result;
>
> looks suboptimal because it calls unbind_to twice.

I noticed that too, and actually coded up something along those lines, 
but decided to discard it as it added complexity and the patch was 
already pretty large.  There is some virtue in having a simpler API, 
even if it's a tad suboptimal.  Perhaps we can think of a way of 
combining SAFE_FREE and unbind_to so that there aren't two different 
ways in the source code of doing the same thing.

To be honest I've never been a fan of 'RETURN_UNGCPRO (expr);', and 
would rather not encourage other macros along those lines.  I was hoping 
that we could get rid of all the GCPRO stuff, and simplify the code 
under the assumption that GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS.

I do like the idea about specbind returning the previous SPECPDL_INDEX, 
as that would simplify the code.





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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-05  8:59 ` Dmitry Antipov
@ 2014-09-05 15:03   ` Paul Eggert
  0 siblings, 0 replies; 23+ messages in thread
From: Paul Eggert @ 2014-09-05 15:03 UTC (permalink / raw
  To: Dmitry Antipov; +Cc: 18410

Dmitry Antipov wrote:
> If __GNUC__, can't we use __attribute__ ((cleanup (freeing_function)))
> for implicit calls
> to SAFE_FREE

We could, but I don't see how this would help.  For non-GNUC we need to 
call the freeing function explicitly anyway, so __attribute__ ((cleanup 
...)) would simply clutter up the source, no?  Or perhaps I'm not 
understanding the suggestion.





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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-05  8:45 ` Dmitry Antipov
  2014-09-05 15:01   ` Paul Eggert
@ 2014-09-05 15:44   ` Stefan Monnier
  2014-09-05 16:04     ` Andreas Schwab
  1 sibling, 1 reply; 23+ messages in thread
From: Stefan Monnier @ 2014-09-05 15:44 UTC (permalink / raw
  To: Dmitry Antipov; +Cc: Paul Eggert, 18410

> USE_SAFE_ALLOCA;                                                    |-
> ptrdiff_t count = SPECPDL_INDEX ();                    |-           |
> ...                                                    | inner bind | outer bind
> Lisp_Object result = unbind_to (count, Fsome_func ()); |-           |
> SAFE_FREE ();                                                       |-
> return result;
>
> looks suboptimal because it calls unbind_to twice.

Only if the object is "too large" and requires heap allocation.

BTW, AFAIK

   Lisp_Object result = unbind_to (count, Fsome_func ());

can always be written

   Lisp_Object result = Fsome_func ();
   unbind_to (count, Qnil);

which I find more readable (if it were me, unbind_to would take
a single arg and return void).


        Stefan





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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-05 15:44   ` Stefan Monnier
@ 2014-09-05 16:04     ` Andreas Schwab
  2014-09-05 17:22       ` Stefan Monnier
  0 siblings, 1 reply; 23+ messages in thread
From: Andreas Schwab @ 2014-09-05 16:04 UTC (permalink / raw
  To: Stefan Monnier; +Cc: Dmitry Antipov, 18410, Paul Eggert

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> BTW, AFAIK
>
>    Lisp_Object result = unbind_to (count, Fsome_func ());
>
> can always be written
>
>    Lisp_Object result = Fsome_func ();
>    unbind_to (count, Qnil);

Only if the result is already protected, since unbind_to can GC.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."





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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-05 16:04     ` Andreas Schwab
@ 2014-09-05 17:22       ` Stefan Monnier
  0 siblings, 0 replies; 23+ messages in thread
From: Stefan Monnier @ 2014-09-05 17:22 UTC (permalink / raw
  To: Andreas Schwab; +Cc: Dmitry Antipov, 18410, Paul Eggert

>> Lisp_Object result = unbind_to (count, Fsome_func ());
>> can always be written
>> Lisp_Object result = Fsome_func ();
>> unbind_to (count, Qnil);
> Only if the result is already protected, since unbind_to can GC.

Indeed, if you need GCPRO, then it's not necessarily true any more.


        Stefan





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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-05  6:08 bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation Paul Eggert
  2014-09-05  8:45 ` Dmitry Antipov
  2014-09-05  8:59 ` Dmitry Antipov
@ 2014-09-07  7:20 ` Paul Eggert
  2014-09-07 17:09   ` Eli Zaretskii
  2 siblings, 1 reply; 23+ messages in thread
From: Paul Eggert @ 2014-09-07  7:20 UTC (permalink / raw
  To: 18410-done

I installed the patch as trunk bzr 117829 and am marking this as done.





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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-07  7:20 ` Paul Eggert
@ 2014-09-07 17:09   ` Eli Zaretskii
  2014-09-07 20:33     ` Paul Eggert
  0 siblings, 1 reply; 23+ messages in thread
From: Eli Zaretskii @ 2014-09-07 17:09 UTC (permalink / raw
  To: Paul Eggert; +Cc: 18410

> Date: Sun, 07 Sep 2014 00:20:33 -0700
> From: Paul Eggert <eggert@cs.ucla.edu>
> 
> I installed the patch as trunk bzr 117829 and am marking this as done.

What is the rationale for tests such as this one in callproc.c:

    if (MAX_ALLOCA / sizeof *env - 2 < new_length)
      exec_failed (new_argv[0], ENOMEM);

MAX_ALLOCA is a relatively small number compared to the stack space
available on modern systems, so I see no reason to fail and exit in
these cases, it sounds too drastic.

Perhaps we should have a separate constant with platform-specific
value, if we want such tests.  Or maybe make them conditional on
ENABLE_CHECKING.





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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-07 17:09   ` Eli Zaretskii
@ 2014-09-07 20:33     ` Paul Eggert
  2014-09-08  2:22       ` Stefan Monnier
  2014-09-08  2:36       ` Eli Zaretskii
  0 siblings, 2 replies; 23+ messages in thread
From: Paul Eggert @ 2014-09-07 20:33 UTC (permalink / raw
  To: Eli Zaretskii; +Cc: 18410

Eli Zaretskii wrote:
> MAX_ALLOCA is a relatively small number compared to the stack space
> available on modern systems, so I see no reason to fail and exit in
> these cases, it sounds too drastic.

Usually MAX_ALLOCA-related code falls back on malloc, and does not exit 
merely because a request was larger.  callproc.c's child_setup function 
is special, though, as it executes in a vforked child that cannot safely 
call malloc because that would screw up the parent's malloc arena.  In 
this special case the child exits (Emacs itself doesn't), so it's not 
that drastic.  It'd be nicer if Emacs would allocate the memory before 
vforking the child, as that would avoid the limitation, but I daresay 
it's not urgent to fix this.  It should be commented better, though, and 
I gave that a shot in trunk bzr 117837.

Quite possibly we should increase MAX_ALLOCA on many modern systems.  As 
I recall we last discussed that in July, and Stefan was worried about 
max-lisp-eval-depth * MAX_ALLOCA * N overflowing the C stack, where N is 
the maximum nesting depth of SAFE_ALLOCA-using C functions between Lisp 
functions.  Perhaps some of that discussion is moot now, with the stack 
overflow checking that Dmitry added last month?





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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-07 20:33     ` Paul Eggert
@ 2014-09-08  2:22       ` Stefan Monnier
  2014-09-08  2:35         ` Eli Zaretskii
  2014-09-08  2:38         ` Paul Eggert
  2014-09-08  2:36       ` Eli Zaretskii
  1 sibling, 2 replies; 23+ messages in thread
From: Stefan Monnier @ 2014-09-08  2:22 UTC (permalink / raw
  To: Paul Eggert; +Cc: 18410

> Usually MAX_ALLOCA-related code falls back on malloc, and does not exit
> merely because a request was larger.  callproc.c's child_setup function is

MAX_ALLOCA is chosen small so that we can allocate several/many objects
of size MAX_ALLOCA.  Whereas in this case, after this alloca we're not
expected to use up the stack much more (we're about to `exec' anyway,
right?).  So MAX_ALLOCA is much too conservative for this case.


        Stefan





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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-08  2:22       ` Stefan Monnier
@ 2014-09-08  2:35         ` Eli Zaretskii
  2014-09-08  2:43           ` Stefan Monnier
  2014-09-08  2:38         ` Paul Eggert
  1 sibling, 1 reply; 23+ messages in thread
From: Eli Zaretskii @ 2014-09-08  2:35 UTC (permalink / raw
  To: Stefan Monnier; +Cc: eggert, 18410

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Eli Zaretskii <eliz@gnu.org>,  18410@debbugs.gnu.org
> Date: Sun, 07 Sep 2014 22:22:23 -0400
> 
> > Usually MAX_ALLOCA-related code falls back on malloc, and does not exit
> > merely because a request was larger.  callproc.c's child_setup function is
> 
> MAX_ALLOCA is chosen small so that we can allocate several/many objects
> of size MAX_ALLOCA.  Whereas in this case, after this alloca we're not
> expected to use up the stack much more (we're about to `exec' anyway,
> right?).  So MAX_ALLOCA is much too conservative for this case.

Indeed, I agree.  So I think we should increase the limit in
callproc.c, especially if we are going to keep the exit with failed
status when the limit is exceeded.





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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-07 20:33     ` Paul Eggert
  2014-09-08  2:22       ` Stefan Monnier
@ 2014-09-08  2:36       ` Eli Zaretskii
  2014-09-08 12:48         ` Stefan Monnier
  1 sibling, 1 reply; 23+ messages in thread
From: Eli Zaretskii @ 2014-09-08  2:36 UTC (permalink / raw
  To: Paul Eggert; +Cc: 18410

> Date: Sun, 07 Sep 2014 13:33:10 -0700
> From: Paul Eggert <eggert@cs.ucla.edu>
> CC: 18410@debbugs.gnu.org
> 
> Perhaps some of that discussion is moot now, with the stack overflow
> checking that Dmitry added last month?

I'd say it's definitely moot on systems where that stack-overflow code
is working.





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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-08  2:22       ` Stefan Monnier
  2014-09-08  2:35         ` Eli Zaretskii
@ 2014-09-08  2:38         ` Paul Eggert
  2014-09-08  3:17           ` Demetrios Obenour
  2014-09-08  7:26           ` Dmitry Antipov
  1 sibling, 2 replies; 23+ messages in thread
From: Paul Eggert @ 2014-09-08  2:38 UTC (permalink / raw
  To: Stefan Monnier; +Cc: 18410

Stefan Monnier wrote:
> MAX_ALLOCA is chosen small so that we can allocate several/many objects
> of size MAX_ALLOCA.

That's one reason, but another is that stack-overflow checking often 
relies on guard pages.  If we blindly increase MAX_ALLOCA (or some 
variant of it, just for call-process) Emacs could bypass stack-overflow 
checking, resulting in behavior that could be worse than simply dumping 
core.

If I understand things correctly, Dmitry's recent stack-overflow changes 
don't affect this, as they don't deal with the guard-page region size.





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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-08  2:35         ` Eli Zaretskii
@ 2014-09-08  2:43           ` Stefan Monnier
  0 siblings, 0 replies; 23+ messages in thread
From: Stefan Monnier @ 2014-09-08  2:43 UTC (permalink / raw
  To: Eli Zaretskii; +Cc: eggert, 18410

> Indeed, I agree.  So I think we should increase the limit in
> callproc.c, especially if we are going to keep the exit with failed
> status when the limit is exceeded.

I don't even see any need for checking at all.


        Stefan





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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-08  2:38         ` Paul Eggert
@ 2014-09-08  3:17           ` Demetrios Obenour
  2014-09-08  3:19             ` Daniel Colascione
  2014-09-08  7:26           ` Dmitry Antipov
  1 sibling, 1 reply; 23+ messages in thread
From: Demetrios Obenour @ 2014-09-08  3:17 UTC (permalink / raw
  To: 'Paul Eggert', 'Stefan Monnier'; +Cc: 18410

This is crucial. Otherwise, a security vulnerability could result.

MAX_ALLOCA should not be larger than the page size for the target architecture.

Demetrios Obenour

-----Original Message-----
From: bug-gnu-emacs-bounces+demetriobenour=gmail.com@gnu.org [mailto:bug-gnu-emacs-bounces+demetriobenour=gmail.com@gnu.org] On Behalf Of Paul Eggert
Sent: Sunday, September 7, 2014 10:38 PM
To: Stefan Monnier
Cc: 18410@debbugs.gnu.org
Subject: bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.

Stefan Monnier wrote:
> MAX_ALLOCA is chosen small so that we can allocate several/many 
> objects of size MAX_ALLOCA.

That's one reason, but another is that stack-overflow checking often relies on guard pages.  If we blindly increase MAX_ALLOCA (or some variant of it, just for call-process) Emacs could bypass stack-overflow checking, resulting in behavior that could be worse than simply dumping core.

If I understand things correctly, Dmitry's recent stack-overflow changes don't affect this, as they don't deal with the guard-page region size.









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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-08  3:17           ` Demetrios Obenour
@ 2014-09-08  3:19             ` Daniel Colascione
  2014-09-08  3:20               ` Demetrios Obenour
  0 siblings, 1 reply; 23+ messages in thread
From: Daniel Colascione @ 2014-09-08  3:19 UTC (permalink / raw
  To: Demetrios Obenour, 'Paul Eggert',
	'Stefan Monnier'; +Cc: 18410

[-- Attachment #1: Type: text/plain, Size: 267 bytes --]

On 09/07/2014 08:17 PM, Demetrios Obenour wrote:
> This is crucial. Otherwise, a security vulnerability could result.
> 
> MAX_ALLOCA should not be larger than the page size for the target architecture.

You could just touch every page inside a large alloca.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-08  3:19             ` Daniel Colascione
@ 2014-09-08  3:20               ` Demetrios Obenour
  0 siblings, 0 replies; 23+ messages in thread
From: Demetrios Obenour @ 2014-09-08  3:20 UTC (permalink / raw
  To: 'Daniel Colascione', 'Paul Eggert',
	'Stefan Monnier'
  Cc: 18410

That would work also, and is probably the best approach.

-----Original Message-----
From: Daniel Colascione [mailto:dancol@dancol.org] 
Sent: Sunday, September 7, 2014 11:20 PM
To: Demetrios Obenour; 'Paul Eggert'; 'Stefan Monnier'
Cc: 18410@debbugs.gnu.org
Subject: Re: bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.

On 09/07/2014 08:17 PM, Demetrios Obenour wrote:
> This is crucial. Otherwise, a security vulnerability could result.
> 
> MAX_ALLOCA should not be larger than the page size for the target architecture.

You could just touch every page inside a large alloca.







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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-08  2:38         ` Paul Eggert
  2014-09-08  3:17           ` Demetrios Obenour
@ 2014-09-08  7:26           ` Dmitry Antipov
  1 sibling, 0 replies; 23+ messages in thread
From: Dmitry Antipov @ 2014-09-08  7:26 UTC (permalink / raw
  To: Paul Eggert, Stefan Monnier; +Cc: 18410

On 09/08/2014 06:38 AM, Paul Eggert wrote:

> If I understand things correctly, Dmitry's recent stack-overflow changes
> don't  affect this, as they don't deal with the guard-page region size.

Yes.  Guard-page approach has an unsolvable problem with dynamically adjusted
stack size (prlimit on GNU/Linux) - you just don't know where the guard page
should be, and there is no OS-level capability to notify an application about
stack size change.

Dmitry






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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-08  2:36       ` Eli Zaretskii
@ 2014-09-08 12:48         ` Stefan Monnier
  2014-09-09 13:17           ` Eli Zaretskii
  0 siblings, 1 reply; 23+ messages in thread
From: Stefan Monnier @ 2014-09-08 12:48 UTC (permalink / raw
  To: Eli Zaretskii; +Cc: Paul Eggert, 18410

>> Perhaps some of that discussion is moot now, with the stack overflow
>> checking that Dmitry added last month?
> I'd say it's definitely moot on systems where that stack-overflow code
> is working.

I disagree.  Even if the new stack-overflow code works, it doesn't
change the fact that a stack-overflow is a problem for the end-user and
we should try to avoid causing such things.

IOW, Dmitry's overflow-handling is good because it makes the failure
a bit cleaner, but it's still a failure that we should strive to avoid.


        Stefan





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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-08 12:48         ` Stefan Monnier
@ 2014-09-09 13:17           ` Eli Zaretskii
  2014-09-09 13:49             ` Stefan Monnier
  0 siblings, 1 reply; 23+ messages in thread
From: Eli Zaretskii @ 2014-09-09 13:17 UTC (permalink / raw
  To: Stefan Monnier; +Cc: eggert, 18410

> From: Stefan Monnier <monnier@IRO.UMontreal.CA>
> Cc: Paul Eggert <eggert@cs.ucla.edu>, 18410@debbugs.gnu.org
> Date: Mon, 08 Sep 2014 08:48:50 -0400
> 
> >> Perhaps some of that discussion is moot now, with the stack overflow
> >> checking that Dmitry added last month?
> > I'd say it's definitely moot on systems where that stack-overflow code
> > is working.
> 
> I disagree.  Even if the new stack-overflow code works, it doesn't
> change the fact that a stack-overflow is a problem for the end-user and
> we should try to avoid causing such things.
> 
> IOW, Dmitry's overflow-handling is good because it makes the failure
> a bit cleaner, but it's still a failure that we should strive to avoid.

Actually, we are in violent agreement.  The point I was making is that
given that we want to check for stack overflow, we don't need 2 such
checks.  I didn't mean at all to say that we should be less careful
about avoiding stack overflows.





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

* bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation.
  2014-09-09 13:17           ` Eli Zaretskii
@ 2014-09-09 13:49             ` Stefan Monnier
  0 siblings, 0 replies; 23+ messages in thread
From: Stefan Monnier @ 2014-09-09 13:49 UTC (permalink / raw
  To: Eli Zaretskii; +Cc: eggert, 18410

> Actually, we are in violent agreement.  The point I was making is that
> given that we want to check for stack overflow, we don't need 2 such
> checks.  I didn't mean at all to say that we should be less careful
> about avoiding stack overflows.

Good.

I just wanted to clarify since the "moot discussion" was about
increasing MAX_ALLOCA, which would increase the risk of stack overflow.


        Stefan





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

end of thread, other threads:[~2014-09-09 13:49 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-09-05  6:08 bug#18410: Use SAFE_ALLOCA etc. to avoid unbounded stack allocation Paul Eggert
2014-09-05  8:45 ` Dmitry Antipov
2014-09-05 15:01   ` Paul Eggert
2014-09-05 15:44   ` Stefan Monnier
2014-09-05 16:04     ` Andreas Schwab
2014-09-05 17:22       ` Stefan Monnier
2014-09-05  8:59 ` Dmitry Antipov
2014-09-05 15:03   ` Paul Eggert
2014-09-07  7:20 ` Paul Eggert
2014-09-07 17:09   ` Eli Zaretskii
2014-09-07 20:33     ` Paul Eggert
2014-09-08  2:22       ` Stefan Monnier
2014-09-08  2:35         ` Eli Zaretskii
2014-09-08  2:43           ` Stefan Monnier
2014-09-08  2:38         ` Paul Eggert
2014-09-08  3:17           ` Demetrios Obenour
2014-09-08  3:19             ` Daniel Colascione
2014-09-08  3:20               ` Demetrios Obenour
2014-09-08  7:26           ` Dmitry Antipov
2014-09-08  2:36       ` Eli Zaretskii
2014-09-08 12:48         ` Stefan Monnier
2014-09-09 13:17           ` Eli Zaretskii
2014-09-09 13:49             ` 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.