summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Blake <ebb9@byu.net>2007-11-13 11:59:43 -0700
committerEric Blake <ebb9@byu.net>2007-11-13 11:59:57 -0700
commit6bfe1ba306cacd8d9316647f3b9f276cf56b31a8 (patch)
tree8b5539aed5668c1ad62ee6c3ca23b9f84b29af35
parent143b597a5a4d66362c29709cce78b7bd10c64817 (diff)
downloadm4-6bfe1ba306cacd8d9316647f3b9f276cf56b31a8.tar.gz
Fix memory leak in tail recursion.
* src/input.c (push_string_init): Let go of memory earlier. (next_char_1): Make end of string detection reliable. (match_input): Simplify use of push_string_init. * NEWS: Document this fix. Signed-off-by: Eric Blake <ebb9@byu.net>
-rw-r--r--ChangeLog8
-rw-r--r--NEWS1
-rw-r--r--src/input.c53
3 files changed, 50 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index 86d8ad43..b52f3e07 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-11-13 Eric Blake <ebb9@byu.net>
+
+ Fix memory leak in tail recursion.
+ * src/input.c (push_string_init): Let go of memory earlier.
+ (next_char_1): Make end of string detection reliable.
+ (match_input): Simplify use of push_string_init.
+ * NEWS: Document this fix.
+
2007-11-07 Eric Blake <ebb9@byu.net>
* doc/m4.texinfo (Pseudo Arguments): Test more corner cases.
diff --git a/NEWS b/NEWS
index 6d667f0e..b92630b8 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,7 @@ Version 1.4.11 - ?? ??? 2007, by ???? (git version 1.4.10a-*)
possible to concatenate a builtin macro with anything else.
* Several improvements in `index', `regexp', and `patsubst' builtins to
speed up typical Autoconf usage.
+* Memory usage is greatly reduced in recursive macros.
* A number of portability improvements inherited from gnulib.
Version 1.4.10 - 09 Jul 2007, by Eric Blake (CVS version 1.4.9c)
diff --git a/src/input.c b/src/input.c
index 23903f39..3ef7b83e 100644
--- a/src/input.c
+++ b/src/input.c
@@ -241,7 +241,37 @@ push_macro (builtin_func *func)
struct obstack *
push_string_init (void)
{
+ /* Free any memory occupied by completely parsed strings. */
+ bool pruning = true;
assert (next == NULL);
+ while (isp && pruning)
+ {
+ switch (isp->type)
+ {
+ case INPUT_STRING:
+ if (*isp->u.u_s.string)
+ pruning = false;
+ break;
+
+ case INPUT_FILE:
+ case INPUT_MACRO:
+ pruning = false;
+ break;
+
+ default:
+ assert (!"push_string_init");
+ abort ();
+ }
+ if (pruning)
+ {
+ next = isp;
+ isp = isp->prev;
+ }
+ }
+ if (next)
+ obstack_free (current_input, next);
+
+ /* Reserve the next location on the obstack. */
next = (input_block *) obstack_alloc (current_input,
sizeof (struct input_block));
next->type = INPUT_STRING;
@@ -497,9 +527,12 @@ next_char_1 (void)
switch (isp->type)
{
case INPUT_STRING:
- ch = to_uchar (*isp->u.u_s.string++);
+ ch = to_uchar (*isp->u.u_s.string);
if (ch != '\0')
- return ch;
+ {
+ *isp->u.u_s.string++;
+ return ch;
+ }
break;
case INPUT_FILE:
@@ -536,10 +569,10 @@ next_char_1 (void)
}
}
-/*------------------------------------------------------------------------.
-| skip_line () simply discards all immediately following characters, upto |
-| the first newline. It is only used from m4_dnl (). |
-`------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------.
+| skip_line () simply discards all immediately following characters, |
+| up to the first newline. It is only used from m4_dnl (). |
+`-------------------------------------------------------------------*/
void
skip_line (void)
@@ -607,12 +640,8 @@ match_input (const char *s, bool consume)
}
/* Failed or shouldn't consume, push back input. */
- {
- struct obstack *h = push_string_init ();
-
- /* `obstack_grow' may be macro evaluating its arg 1 several times. */
- obstack_grow (h, t, n);
- }
+ push_string_init ();
+ obstack_grow (current_input, t, n);
push_string_finish ();
return result;
}