diff options
author | Eric Blake <ebb9@byu.net> | 2007-11-13 11:59:43 -0700 |
---|---|---|
committer | Eric Blake <ebb9@byu.net> | 2007-11-13 11:59:57 -0700 |
commit | 6bfe1ba306cacd8d9316647f3b9f276cf56b31a8 (patch) | |
tree | 8b5539aed5668c1ad62ee6c3ca23b9f84b29af35 | |
parent | 143b597a5a4d66362c29709cce78b7bd10c64817 (diff) | |
download | m4-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-- | ChangeLog | 8 | ||||
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | src/input.c | 53 |
3 files changed, 50 insertions, 12 deletions
@@ -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. @@ -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; } |