[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Preventing stack overflows with alloca.
From: |
Kim F. Storm |
Subject: |
Preventing stack overflows with alloca. |
Date: |
18 Jun 2004 12:14:41 +0200 |
User-agent: |
Gnus/5.09 (Gnus v5.9.0) Emacs/21.3.50 |
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 <address@hidden> http://www.cua.dk
- Preventing stack overflows with alloca.,
Kim F. Storm <=
- Re: Preventing stack overflows with alloca., Kenichi Handa, 2004/06/18
- Re: Preventing stack overflows with alloca., Kim F. Storm, 2004/06/18
- Re: Preventing stack overflows with alloca., Kenichi Handa, 2004/06/18
- Re: Preventing stack overflows with alloca., Richard Stallman, 2004/06/18
- Re: Preventing stack overflows with alloca., Kim F. Storm, 2004/06/20
- Re: Preventing stack overflows with alloca., Kim F. Storm, 2004/06/21
- Re: Preventing stack overflows with alloca., Richard Stallman, 2004/06/22