unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Preventing stack overflows with alloca.
@ 2004-06-18 10:14 Kim F. Storm
  2004-06-18 11:13 ` Kenichi Handa
  0 siblings, 1 reply; 11+ messages in thread
From: Kim F. Storm @ 2004-06-18 10:14 UTC (permalink / raw)



Jan just installed a change to fns.c to use xmalloc instead of
alloca in string_to_multibyte.

Always using xmalloc seems a bit expensive, so I suggest
only using it if the size is > MAX_ALLOCA (already defined
in fns.c).

But there are other risky uses of alloca, so I suggest the 
patch below which takes care of the problems in fns.c.  


It might be necessary to unwind protect the xfree calls,
but in any case, a memory leak is better than a trap ...

An simple alternative to unwind protect would be to link such
temporary xmalloc blocks on a global xfree_temp_list around the
problematic code (if the code runs ok, we remove the pointer again)
then the main interpreter loop could free such temporary memory
blocks.


Something like this (untested):

void *xfree_temp_list = 0;

void *xmalloc_temp(int size)
{
  void **ptr;
  ptr = (void **)xmalloc(size + sizeof(void *));
  *ptr = xfree_temp_list;
  xfree_temp_list = (void *)ptr;
  return (void *)(ptr+1);
}

void xfree_temp(void *ptr)
{
  assert(xfree_temp_list == ptr);

  xfree_temp_list = *--(void **)ptr;
  xfree(ptr);
}


and then in the main loop something like this:

while (xfree_temp_list)
  {
    void *ptr = xfree_temp_list;
    xfree_temp_list = *(void **)ptr;
    xfree(ptr);
  }


Here is the patch without using xmalloc_temp/xfree_temp:


*** fns.c	18 Jun 2004 10:05:47 +0200	1.364
--- fns.c	18 Jun 2004 10:29:46 +0200	
***************
*** 75,80 ****
--- 75,84 ----
  
  extern Lisp_Object Qinput_method_function;
  
+ /* Don't use alloca for regions larger than this, lest we overflow
+    their stack.  */
+ #define MAX_ALLOCA 16*1024
+ 
  static int internal_equal ();
  
  extern long get_random ();
***************
*** 994,999 ****
--- 998,1004 ----
  {
    unsigned char *buf;
    int nbytes;
+   Lisp_Object ret;
  
    if (STRING_MULTIBYTE (string))
      return string;
***************
*** 1005,1015 ****
    if (nbytes == SBYTES (string))
      return string;
  
!   buf = (unsigned char *) alloca (nbytes);
    copy_text (SDATA (string), buf, SBYTES (string),
  	     0, 1);
  
!   return make_multibyte_string (buf, SCHARS (string), nbytes);
  }
  
  
--- 1010,1029 ----
    if (nbytes == SBYTES (string))
      return string;
  
!   if (nbytes > MAX_ALLOCA)
!     buf = (unsigned char *) xmalloc (nbytes);
!   else
!     buf = (unsigned char *) alloca (nbytes);
! 
    copy_text (SDATA (string), buf, SBYTES (string),
  	     0, 1);
  
!   ret = make_multibyte_string (buf, SCHARS (string), nbytes);
! 
!   if (nbytes > MAX_ALLOCA)
!     xfree (buf);
! 
!   return ret;
  }
  
  
***************
*** 1024,1029 ****
--- 1038,1044 ----
  {
    unsigned char *buf;
    int nbytes;
+   Lisp_Object ret;
  
    if (STRING_MULTIBYTE (string))
      return string;
***************
*** 1034,1044 ****
    if (nbytes == SBYTES (string))
      return make_multibyte_string (SDATA (string), nbytes, nbytes);
  
!   buf = (unsigned char *) alloca (nbytes);
    bcopy (SDATA (string), buf, SBYTES (string));
    str_to_multibyte (buf, nbytes, SBYTES (string));
  
!   return make_multibyte_string (buf, SCHARS (string), nbytes);
  }
  
  
--- 1049,1067 ----
    if (nbytes == SBYTES (string))
      return make_multibyte_string (SDATA (string), nbytes, nbytes);
  
!   if (nbytes > MAX_ALLOCA)
!     buf = (unsigned char *) xmalloc (nbytes);
!   else
!     buf = (unsigned char *) alloca (nbytes);
! 
    bcopy (SDATA (string), buf, SBYTES (string));
    str_to_multibyte (buf, nbytes, SBYTES (string));
+   ret = make_multibyte_string (buf, SCHARS (string), nbytes);
  
!   if (nbytes > MAX_ALLOCA)
!     xfree (buf);
! 
!   return ret;
  }
  
  
***************
*** 1049,1070 ****
       Lisp_Object string;
  {
    unsigned char *buf;
    Lisp_Object ret;
  
    if (! STRING_MULTIBYTE (string))
      return string;
  
!   /* We can not use alloca here, because string might be very long.
       For example when selecting megabytes of text and then pasting it to
       another application.  */
!   buf = (unsigned char *) xmalloc (SCHARS (string));
  
    copy_text (SDATA (string), buf, SBYTES (string),
  	     1, 0);
  
    ret = make_unibyte_string (buf, SCHARS (string));
  
!   xfree (buf);
  
    return ret;
  }
--- 1072,1100 ----
       Lisp_Object string;
  {
    unsigned char *buf;
+   int nbytes;
    Lisp_Object ret;
  
    if (! STRING_MULTIBYTE (string))
      return string;
  
!   /* We can not just use alloca here, because string might be very long.
       For example when selecting megabytes of text and then pasting it to
       another application.  */
! 
!   nbytes = SCHARS (string);
!   if (nbytes > MAX_ALLOCA)
!     buf = (unsigned char *) xmalloc (nbytes);
!   else
!     buf = (unsigned char *) alloca (nbytes);
  
    copy_text (SDATA (string), buf, SBYTES (string),
  	     1, 0);
  
    ret = make_unibyte_string (buf, SCHARS (string));
  
!   if (nbytes > MAX_ALLOCA)
!     xfree (buf);
  
    return ret;
  }
***************
*** 2985,2993 ****
       (function, sequence, separator)
       Lisp_Object function, sequence, separator;
  {
!   Lisp_Object len;
    register int leni;
!   int nargs;
    register Lisp_Object *args;
    register int i;
    struct gcpro gcpro1;
--- 3015,3023 ----
       (function, sequence, separator)
       Lisp_Object function, sequence, separator;
  {
!   Lisp_Object len, ret;
    register int leni;
!   int nargs, nbytes;
    register Lisp_Object *args;
    register int i;
    struct gcpro gcpro1;
***************
*** 2997,3003 ****
    nargs = leni + leni - 1;
    if (nargs < 0) return build_string ("");
  
!   args = (Lisp_Object *) alloca (nargs * sizeof (Lisp_Object));
  
    GCPRO1 (separator);
    mapcar1 (leni, args, function, sequence);
--- 3027,3037 ----
    nargs = leni + leni - 1;
    if (nargs < 0) return build_string ("");
  
!   nbytes = nargs * sizeof (Lisp_Object);
!   if (nbytes > MAX_ALLOCA)
!     args = (Lisp_Object *) xmalloc (nbytes);
!   else
!     args = (Lisp_Object *) alloca (nbytes);
  
    GCPRO1 (separator);
    mapcar1 (leni, args, function, sequence);
***************
*** 3009,3015 ****
    for (i = 1; i < nargs; i += 2)
      args[i] = separator;
  
!   return Fconcat (nargs, args);
  }
  
  DEFUN ("mapcar", Fmapcar, Smapcar, 2, 2, 0,
--- 3043,3054 ----
    for (i = 1; i < nargs; i += 2)
      args[i] = separator;
  
!   ret = Fconcat (nargs, args);
! 
!   if (nbytes > MAX_ALLOCA)
!     xfree (args);
! 
!   return ret;
  }
  
  DEFUN ("mapcar", Fmapcar, Smapcar, 2, 2, 0,
***************
*** 3019,3035 ****
       (function, sequence)
       Lisp_Object function, sequence;
  {
!   register Lisp_Object len;
!   register int leni;
!   register Lisp_Object *args;
  
    len = Flength (sequence);
    leni = XFASTINT (len);
!   args = (Lisp_Object *) alloca (leni * sizeof (Lisp_Object));
  
    mapcar1 (leni, args, function, sequence);
  
!   return Flist (leni, args);
  }
  
  DEFUN ("mapc", Fmapc, Smapc, 2, 2, 0,
--- 3058,3084 ----
       (function, sequence)
       Lisp_Object function, sequence;
  {
!   Lisp_Object len, ret;
!   int leni, nbytes;
!   Lisp_Object *args;
  
    len = Flength (sequence);
    leni = XFASTINT (len);
! 
!   nbytes = leni * sizeof (Lisp_Object);
!   if (nbytes > MAX_ALLOCA)
!     args = (Lisp_Object *) xmalloc (nbytes);
!   else
!     args = (Lisp_Object *) alloca (nbytes);
  
    mapcar1 (leni, args, function, sequence);
  
!   ret = Flist (leni, args);
! 
!   if (nbytes > MAX_ALLOCA)
!     xfree (args);
! 
!   return ret;
  }
  
  DEFUN ("mapc", Fmapc, Smapc, 2, 2, 0,
***************
*** 3644,3653 ****
      }					\
    while (IS_BASE64_IGNORABLE (c))
  
- /* Don't use alloca for regions larger than this, lest we overflow
-    their stack.  */
- #define MAX_ALLOCA 16*1024
- 
  /* Table of characters coding the 64 values.  */
  static char base64_value_to_char[64] =
  {
--- 3693,3698 ----

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

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

end of thread, other threads:[~2004-10-27 17:34 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-06-18 10:14 Preventing stack overflows with alloca Kim F. Storm
2004-06-18 11:13 ` Kenichi Handa
2004-06-18 12:02   ` Kim F. Storm
2004-06-19  0:19     ` Kenichi Handa
2004-06-19  3:19     ` Richard Stallman
2004-06-20 18:56       ` Kim F. Storm
2004-06-21 22:01       ` Kim F. Storm
2004-06-22 23:17         ` Richard Stallman
2004-10-25 17:11   ` Yoichi NAKAYAMA
2004-10-26 14:04     ` Kim F. Storm
2004-10-27 17:34       ` Richard Stallman

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).