index ce2080b7e671e55ffa57fa7c3b9ff6eb44db3e77..b55fe54e84951640ae957f46c61c2237d4a2b2f9 100644 (file)
+2007年11月13日 Eric Blake <ebb9@byu.net>
+
+ Fix memory leak in tail recursion.
+ * m4/input.c (pop_input): Add flag parameter and return type.
+ (next_char): Adjust caller.
+ (m4_push_string_init): Let go of memory earlier.
+
2007年11月07日 Eric Blake <ebb9@byu.net>
* tests/macros.at (Rescanning macros): Test more corner cases.
index 646a16952eb8e606447083809775ce23c41f768f..a8c4f879db4a495b1df8314f02f7647a6e156e7c 100644 (file)
@@ -109,7 +109,7 @@ static void init_builtin_token (m4 *, m4_symbol_value *);
static bool match_input (m4 *, const char *, bool);
static int next_char (m4 *, bool);
static int peek_char (m4 *);
-static void pop_input (m4 *);
+static bool pop_input (m4 *, bool);
static void unget_input (int);
static bool consume_syntax (m4 *, m4_obstack *, unsigned int);
@@ -496,12 +496,11 @@ string_print (m4_input_block *me, m4 *context, m4_obstack *obs)
m4_obstack *
m4_push_string_init (m4 *context)
{
- if (next != NULL)
- {
- assert (!"INTERNAL ERROR: recursive m4_push_string!");
- abort ();
- }
+ /* Free any memory occupied by completely parsed input. */
+ assert (!next);
+ while (isp && pop_input (context, false));
+ /* Reserve the next location on the obstack. */
next = (m4_input_block *) obstack_alloc (current_input,
sizeof (m4_input_block));
next->funcs = &string_funcs;
}
\f
-/* The function pop_input () pops one level of input sources. The
- current_file and current_line are restored as needed. */
-static void
-pop_input (m4 *context)
+/* The function pop_input () pops one level of input sources. If
+ CLEANUP, the current_file and current_line are restored as needed.
+ The return value is false if cleanup is still required, or if the
+ current input source is not at the end. */
+static bool
+pop_input (m4 *context, bool cleanup)
{
m4_input_block *tmp = isp->prev;
+ assert (isp);
+ if (isp->funcs->peek_func (isp) != CHAR_RETRY)
+ return false;
+
if (isp->funcs->clean_func != NULL)
- isp->funcs->clean_func (isp, context);
+ {
+ if (!cleanup)
+ return false;
+ isp->funcs->clean_func (isp, context);
+ }
if (tmp != NULL)
{
isp = tmp;
input_change = true;
+ return true;
}
/* To switch input over to the wrapup stack, main () calls pop_wrapup.
}
/* End of input source --- pop one level. */
- pop_input (context);
+ pop_input (context, true);
}
}