bison-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Valgrind and Bison memory leaks


From: Joel E. Denny
Subject: Valgrind and Bison memory leaks
Date: Fri, 3 Nov 2006 05:14:09 -0500 (EST)

I try to use Valgrind to make sure I don't create new memory leaks in 
Bison.  However, Valgrind's complaints about all the existing memory leaks 
really get in the way.

I'd like to commit the following, which I believe is a significant 
improvement.  There's a lot going on in this patch, so it definitely 
warrants another pair of eyes.

Most importantly, the end of the patch includes a small change to 
lib/quotearg.*, which I see are part of gnulib.  I'll need some guidance 
on whether that change makes sense for gnulib in general and on what to do 
with it.

Index: ChangeLog
===================================================================
RCS file: /sources/bison/bison/ChangeLog,v
retrieving revision 1.1598
diff -p -u -r1.1598 ChangeLog
--- ChangeLog   1 Nov 2006 06:09:40 -0000       1.1598
+++ ChangeLog   3 Nov 2006 10:05:48 -0000
@@ -1,3 +1,60 @@
+2006-11-03  Joel E. Denny  <address@hidden>
+
+       Don't let Bison leak memory except when it complains.
+       * src/files.c (spec_verbose_file, spec_graph_file, spec_defines_file,
+       parser_file_name, all_but_ext, all_but_tab_ext, dir_prefix,
+       src_extension, header_extension): Remove const since they must be
+       freed.
+       (compute_exts_from_gf, compute_exts_from_src): Don't leak temporary
+       values.
+       (compute_file_name_parts, compute_output_file_names): Don't store
+       read-only data in variables that will be freed.
+       (compute_output_file_names): Free all_but_ext, all_but_tab_ext,
+       src_extension, and header_extension.
+       (output_file_names_free): New public function to free
+       spec_verbose_file, spec_graph_file, spec_defines_file,
+       parser_file_name, and dir_prefix.
+       * src/files.h: Update.
+       * src/getargs.c (getargs): Don't store read-only data in variables that
+       will be freed.
+       * src/main.c (main): Invoke output_file_names_free, code_scanner_free
+       (which previously existed but was unused), and quotearg_free.
+       * src/muscle_tab.c (muscle_entry): Rewrite the value field as a union
+       so it can store a `const char *' or a `char *'.
+       (muscle_entry_free): New private function for freeing a muscle_entry
+       and its value if it's a `char *'.
+       (muscle_init): Initialize muscle_table with muscle_entry_free instead
+       of free.
+       (muscle_insert): Create new entries with `const char *' values, and
+       aver that old retrieved entries have `const char *' values.
+       (muscle_grow): Likewise but `char *'.
+       (muscle_code_grow): Go ahead and free the string passed to muscle_grow
+       since it's not needed anymore.
+       (muscle_find): aver that the retrieved entry's value is a `char *'
+       since the only existing caller in Bison modifies the value and always
+       muscle_*grow's the value.
+       (muscle_m4_output): Use the value as a `const char *' regardless of
+       what kind it actually is.
+       * src/muscle_tab.h (muscle_insert): value arg is now a `const char *'.
+       * src/parse-gram.y (%union): Make `chars' field a `const char *', and
+       add a new `char *nonconst_chars' field.
+       ("{...}"): Declare semantic type as nonconst_chars.
+       * src/scan-code.h, scan-code.l (translate_rule_action,
+       translate_symbol_action, translate_code, translate_action): Return
+       `const char *' rather than `char *' since external code should not free
+       these strings.
+       * src/scan-gram.l: Used val->nonconst_chars for BRACED_CODE, which is
+       "{...}" in the parser.
+       * tests/Makefile.am (maintainer-check-valgrind): Set
+       VALGRIND_OPTS='--leak-check=full --show-reacheable=yes' before invoking
+       Valgrind.
+       * tests/calc.at (_AT_DATA_CALC_Y): fclose the FILE* so Valgrind doesn't
+       complain.
+       * tests/testsuite.at (AT_CHECK): Redefine so that running Bison and
+       expecting a non-zero exit status sets --leak-check=summary and
+       --show-reachable=no for Valgrind.  Bison unabashedly leaks memory in
+       this case, and we don't want to hear about it.
+
 2006-10-31  Joel E. Denny  <address@hidden>
 
        Disable unset/unused mid-rule value warnings by default, and recognize
Index: src/files.c
===================================================================
RCS file: /sources/bison/bison/src/files.c,v
retrieving revision 1.97
diff -p -u -r1.97 files.c
--- src/files.c 12 Oct 2006 23:29:52 -0000      1.97
+++ src/files.c 3 Nov 2006 10:05:48 -0000
@@ -48,10 +48,10 @@ struct obstack post_prologue_obstack;
 char const *spec_outfile = NULL;       /* for -o. */
 char const *spec_file_prefix = NULL;   /* for -b. */
 char const *spec_name_prefix = NULL;   /* for -p. */
-char const *spec_verbose_file = NULL;  /* for --verbose. */
-char const *spec_graph_file = NULL;    /* for -g. */
-char const *spec_defines_file = NULL;  /* for --defines. */
-char const *parser_file_name;
+char *spec_verbose_file = NULL;  /* for --verbose. */
+char *spec_graph_file = NULL;    /* for -g. */
+char *spec_defines_file = NULL;  /* for --defines. */
+char *parser_file_name;
 
 uniqstr grammar_file = NULL;
 uniqstr current_file = NULL;
@@ -72,14 +72,14 @@ uniqstr current_file = NULL;
    empty string (meaning the current directory); otherwise it is
    `dir/'.  */
 
-static char const *all_but_ext;
-static char const *all_but_tab_ext;
-char const *dir_prefix;
+static char *all_but_ext;
+static char *all_but_tab_ext;
+char *dir_prefix;
 
 /* C source file extension (the parser source).  */
-static char const *src_extension = NULL;
+static char *src_extension = NULL;
 /* Header file extension (if option ``-d'' is specified).  */
-static char const *header_extension = NULL;
+static char *header_extension = NULL;
 
 /*-----------------------------------------------------------------.
 | Return a newly allocated string composed of the concatenation of |
@@ -157,10 +157,13 @@ tr (const char *in, char from, char to)
 static void
 compute_exts_from_gf (const char *ext)
 {
-  src_extension = tr (ext, 'y', 'c');
-  src_extension = tr (src_extension, 'Y', 'C');
-  header_extension = tr (ext, 'y', 'h');
-  header_extension = tr (header_extension, 'Y', 'H');
+  char *tmp;
+  tmp = tr (ext, 'y', 'c');
+  src_extension = tr (tmp, 'Y', 'C');
+  free (tmp);
+  tmp = tr (ext, 'y', 'h');
+  header_extension = tr (tmp, 'Y', 'H');
+  free (tmp);
 }
 
 /* Compute extensions from the given c source file extension.  */
@@ -170,9 +173,11 @@ compute_exts_from_src (const char *ext)
   /* We use this function when the user specifies `-o' or `--output',
      so the extenions must be computed unconditionally from the file name
      given by this option.  */
+  char *tmp;
   src_extension = xstrdup (ext);
-  header_extension = tr (ext, 'c', 'h');
-  header_extension = tr (header_extension, 'C', 'H');
+  tmp = tr (ext, 'c', 'h');
+  header_extension = tr (tmp, 'C', 'H');
+  free (tmp);
 }
 
 
@@ -270,14 +275,14 @@ compute_file_name_parts (void)
       else if (yacc_flag)
        {
          /* If --yacc, then the output is `y.tab.c'.  */
-         dir_prefix = "";
-         all_but_tab_ext = "y";
+         dir_prefix = xstrdup ("");
+         all_but_tab_ext = xstrdup ("y");
        }
       else
        {
          /* Otherwise, ALL_BUT_TAB_EXT is computed from the input
             grammar: `foo/bar.yy' => `bar'.  */
-         dir_prefix = "";
+         dir_prefix = xstrdup ("");
          all_but_tab_ext =
            xstrndup (base, (strlen (base) - (ext ? strlen (ext) : 0)));
        }
@@ -306,12 +311,13 @@ compute_output_file_names (void)
 
   /* If not yet done. */
   if (!src_extension)
-    src_extension = ".c";
+    src_extension = xstrdup (".c");
   if (!header_extension)
-    header_extension = ".h";
+    header_extension = xstrdup (".h");
 
   name[names++] = parser_file_name =
-    spec_outfile ? spec_outfile : concat2 (all_but_ext, src_extension);
+    spec_outfile
+    ? xstrdup (spec_outfile) : concat2 (all_but_ext, src_extension);
 
   if (defines_flag)
     {
@@ -337,4 +343,19 @@ compute_output_file_names (void)
     for (i = 0; i < j; i++)
       if (strcmp (name[i], name[j]) == 0)
        warn (_("conflicting outputs to file %s"), quote (name[i]));
+
+  free (all_but_ext);
+  free (all_but_tab_ext);
+  free (src_extension);
+  free (header_extension);
+}
+
+void
+output_file_names_free (void)
+{
+  free (spec_verbose_file);
+  free (spec_graph_file);
+  free (spec_defines_file);
+  free (parser_file_name);
+  free (dir_prefix);
 }
Index: src/files.h
===================================================================
RCS file: /sources/bison/bison/src/files.h,v
retrieving revision 1.41
diff -p -u -r1.41 files.h
--- src/files.h 12 Oct 2006 23:29:52 -0000      1.41
+++ src/files.h 3 Nov 2006 10:05:48 -0000
@@ -29,7 +29,7 @@
 extern char const *spec_outfile;
 
 /* File name for the parser (i.e., the one above, or its default.) */
-extern char const *parser_file_name;
+extern char *parser_file_name;
 
 /* Symbol prefix specified with -p, or 0 if no -p.  */
 extern const char *spec_name_prefix;
@@ -38,16 +38,16 @@ extern const char *spec_name_prefix;
 extern char const *spec_file_prefix;
 
 /* --verbose. */
-extern char const *spec_verbose_file;
+extern char *spec_verbose_file;
 
 /* File name specified for the output graph.  */
-extern char const *spec_graph_file;
+extern char *spec_graph_file;
 
 /* File name specified with --defines.  */
-extern char const *spec_defines_file;
+extern char *spec_defines_file;
 
 /* Directory prefix of output file names.  */
-extern char const *dir_prefix;
+extern char *dir_prefix;
 
 
 /* If semantic parser, output a .h file that defines YYSTYPE... */
@@ -63,6 +63,7 @@ extern uniqstr grammar_file;
 extern uniqstr current_file;
 
 void compute_output_file_names (void);
+void output_file_names_free (void);
 
 FILE *xfopen (const char *name, const char *mode);
 void xfclose (FILE *ptr);
Index: src/getargs.c
===================================================================
RCS file: /sources/bison/bison/src/getargs.c,v
retrieving revision 1.84
diff -p -u -r1.84 getargs.c
--- src/getargs.c       1 Nov 2006 06:09:40 -0000       1.84
+++ src/getargs.c       3 Nov 2006 10:05:48 -0000
@@ -408,7 +408,7 @@ getargs (int argc, char *argv[])
        /* Here, the -g and --graph=FILE options are differentiated.  */
        graph_flag = true;
        if (optarg)
-         spec_graph_file = AS_FILE_NAME (optarg);
+         spec_graph_file = xstrdup (AS_FILE_NAME (optarg));
        break;
 
       case 'h':
@@ -426,7 +426,7 @@ getargs (int argc, char *argv[])
        /* Here, the -d and --defines options are differentiated.  */
        defines_flag = true;
        if (optarg)
-         spec_defines_file = AS_FILE_NAME (optarg);
+         spec_defines_file = xstrdup (AS_FILE_NAME (optarg));
        break;
 
       case 'k':
Index: src/main.c
===================================================================
RCS file: /sources/bison/bison/src/main.c,v
retrieving revision 1.90
diff -p -u -r1.90 main.c
--- src/main.c  12 Oct 2006 23:29:52 -0000      1.90
+++ src/main.c  3 Nov 2006 10:05:48 -0000
@@ -26,6 +26,7 @@
 #include <bitset_stats.h>
 #include <bitset.h>
 #include <configmake.h>
+#include <quotearg.h>
 #include <timevar.h>
 
 #include "LR0.h"
@@ -43,6 +44,7 @@
 #include "print_graph.h"
 #include "reader.h"
 #include "reduce.h"
+#include "scan-code.h"
 #include "scan-gram.h"
 #include "symtab.h"
 #include "tables.h"
@@ -168,12 +170,15 @@ main (int argc, char *argv[])
   reduce_free ();
   conflicts_free ();
   grammar_free ();
+  output_file_names_free ();
 
   /* The scanner memory cannot be released right after parsing, as it
      contains things such as user actions, prologue, epilogue etc.  */
   gram_scanner_free ();
   muscle_free ();
   uniqstrs_free ();
+  code_scanner_free ();
+  quotearg_free ();
   timevar_pop (TV_FREE);
 
   if (trace_flag & trace_bitsets)
Index: src/muscle_tab.c
===================================================================
RCS file: /sources/bison/bison/src/muscle_tab.c,v
retrieving revision 1.39
diff -p -u -r1.39 muscle_tab.c
--- src/muscle_tab.c    3 Jan 2006 20:19:41 -0000       1.39
+++ src/muscle_tab.c    3 Nov 2006 10:05:48 -0000
@@ -33,7 +33,11 @@
 typedef struct
 {
   const char *key;
-  char *value;
+  enum { CONST_VALUE, FREEABLE_VALUE } kind;
+  union {
+    const char *const_value;
+    char *freeable_value;
+  } value;
 } muscle_entry;
 
 /* An obstack used to create some entries.  */
@@ -64,6 +68,15 @@ hash_muscle (const void *x, size_t table
 | Also set up the MUSCLE_OBSTACK.                                  |
 `-----------------------------------------------------------------*/
 
+static void
+muscle_entry_free (void *entry)
+{
+  muscle_entry *mentry = entry;
+  if (mentry->kind == FREEABLE_VALUE)
+    free (mentry->value.freeable_value);
+  free (mentry);
+}
+
 void
 muscle_init (void)
 {
@@ -71,7 +84,7 @@ muscle_init (void)
   obstack_init (&muscle_obstack);
 
   muscle_table = hash_initialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
-                                 hash_compare_muscles, free);
+                                 hash_compare_muscles, muscle_entry_free);
 
   /* Version and input file.  */
   MUSCLE_INSERT_STRING ("version", VERSION);
@@ -98,7 +111,7 @@ muscle_free (void)
 `------------------------------------------------------------*/
 
 void
-muscle_insert (const char *key, char *value)
+muscle_insert (const char *key, const char *value)
 {
   muscle_entry probe;
   muscle_entry *entry;
@@ -112,8 +125,11 @@ muscle_insert (const char *key, char *va
       entry = xmalloc (sizeof *entry);
       entry->key = key;
       hash_insert (muscle_table, entry);
+      entry->kind = CONST_VALUE;
     }
-  entry->value = value;
+  else
+    aver (entry->kind == CONST_VALUE);
+  entry->value.const_value = value;
 }
 
 
@@ -138,19 +154,21 @@ muscle_grow (const char *key, const char
       entry = xmalloc (sizeof *entry);
       entry->key = key;
       hash_insert (muscle_table, entry);
-      entry->value = xstrdup (val);
+      entry->kind = FREEABLE_VALUE;
+      entry->value.freeable_value = xstrdup (val);
     }
   else
     {
       /* Grow the current value. */
       char *new_val;
-      obstack_sgrow (&muscle_obstack, entry->value);
-      free (entry->value);
+      aver (entry->kind == FREEABLE_VALUE);
+      obstack_sgrow (&muscle_obstack, entry->value.freeable_value);
+      free (entry->value.freeable_value);
       obstack_sgrow (&muscle_obstack, separator);
       obstack_sgrow (&muscle_obstack, val);
       obstack_1grow (&muscle_obstack, 0);
       new_val = obstack_finish (&muscle_obstack);
-      entry->value = xstrdup (new_val);
+      entry->value.freeable_value = xstrdup (new_val);
       obstack_free (&muscle_obstack, new_val);
     }
 }
@@ -173,6 +191,7 @@ muscle_code_grow (const char *key, const
   obstack_1grow (&muscle_obstack, 0);
   extension = obstack_finish (&muscle_obstack);
   muscle_grow (key, extension, "");
+  obstack_free (&muscle_obstack, extension);
 }
 
 
@@ -206,7 +225,12 @@ muscle_find (const char *key)
 
   probe.key = key;
   result = hash_lookup (muscle_table, &probe);
-  return result ? result->value : NULL;
+  if (result)
+    {
+      aver (result->kind == FREEABLE_VALUE);
+      return result->value.freeable_value;
+    }
+  return NULL;
 }
 
 
@@ -218,7 +242,8 @@ static inline bool
 muscle_m4_output (muscle_entry *entry, FILE *out)
 {
   fprintf (out, "m4_define([b4_%s],\n", entry->key);
-  fprintf (out, "[[%s]])\n\n\n", entry->value);
+  /* Use the value as a CONST_VALUE regardless of what kind it actually is.  */
+  fprintf (out, "[[%s]])\n\n\n", entry->value.const_value);
   return true;
 }
 
Index: src/muscle_tab.h
===================================================================
RCS file: /sources/bison/bison/src/muscle_tab.h,v
retrieving revision 1.17
diff -p -u -r1.17 muscle_tab.h
--- src/muscle_tab.h    8 Oct 2006 11:07:02 -0000       1.17
+++ src/muscle_tab.h    3 Nov 2006 10:05:48 -0000
@@ -24,7 +24,7 @@
 # include "location.h"
 
 void muscle_init (void);
-void muscle_insert (const char *key, char *value);
+void muscle_insert (const char *key, const char *value);
 char *muscle_find (const char *key);
 void muscle_free (void);
 
Index: src/parse-gram.y
===================================================================
RCS file: /sources/bison/bison/src/parse-gram.y,v
retrieving revision 1.95
diff -p -u -r1.95 parse-gram.y
--- src/parse-gram.y    21 Oct 2006 10:03:35 -0000      1.95
+++ src/parse-gram.y    3 Nov 2006 10:05:49 -0000
@@ -99,7 +99,8 @@ static int current_prec = 0;
   symbol *symbol;
   symbol_list *list;
   int integer;
-  char *chars;
+  char *nonconst_chars;
+  char const *chars;
   assoc assoc;
   uniqstr uniqstr;
   unsigned char character;
@@ -183,7 +184,8 @@ static int current_prec = 0;
 
 /* braceless is not to be used for rule or symbol actions, as it
    calls translate_code. */
-%type <chars> STRING "{...}" "%{...%}" EPILOGUE braceless content content.opt
+%type <chars> STRING "%{...%}" EPILOGUE braceless content content.opt
+%type <nonconst_chars> "{...}"
 %printer { fputs (quotearg_style (c_quoting_style, $$), stderr); }
          STRING
 %printer { fprintf (stderr, "{\n%s\n}", $$); }
Index: src/scan-code.h
===================================================================
RCS file: /sources/bison/bison/src/scan-code.h,v
retrieving revision 1.3
diff -p -u -r1.3 scan-code.h
--- src/scan-code.h     13 Jul 2006 08:12:00 -0000      1.3
+++ src/scan-code.h     3 Nov 2006 10:05:49 -0000
@@ -35,13 +35,13 @@ void code_scanner_free (void);
 
 /* The action of the rule R contains $$, $1 etc. referring to the values
    of the rule R. */
-char *translate_rule_action (symbol_list *r);
+const char *translate_rule_action (symbol_list *r);
 
 /* The action A refers to $$ and @$ only, referring to a symbol. */
-char *translate_symbol_action (const char *a, location l);
+const char *translate_symbol_action (const char *a, location l);
 
 /* The action contains no special escapes, just protect M4 special
    symbols.  */
-char *translate_code (const char *a, location l);
+const char *translate_code (const char *a, location l);
 
 #endif /* !SCAN_CODE_H_ */
Index: src/scan-code.l
===================================================================
RCS file: /sources/bison/bison/src/scan-code.l,v
retrieving revision 1.13
diff -p -u -r1.13 scan-code.l
--- src/scan-code.l     15 Sep 2006 16:34:48 -0000      1.13
+++ src/scan-code.l     3 Nov 2006 10:05:49 -0000
@@ -372,7 +372,7 @@ handle_action_at (symbol_list *rule, cha
    translation is for \a rule, in the context \a sc_context
    (SC_RULE_ACTION, SC_SYMBOL_ACTION, INITIAL).  */
 
-static char *
+static const char *
 translate_action (int sc_context, symbol_list *rule, const char *a, location l)
 {
   char *res;
@@ -394,20 +394,20 @@ translate_action (int sc_context, symbol
   return res;
 }
 
-char *
+const char *
 translate_rule_action (symbol_list *rule)
 {
   return translate_action (SC_RULE_ACTION, rule, rule->action,
                           rule->action_location);
 }
 
-char *
+const char *
 translate_symbol_action (const char *a, location l)
 {
   return translate_action (SC_SYMBOL_ACTION, NULL, a, l);
 }
 
-char *
+const char *
 translate_code (const char *a, location l)
 {
   return translate_action (INITIAL, NULL, a, l);
Index: src/scan-gram.l
===================================================================
RCS file: /sources/bison/bison/src/scan-gram.l,v
retrieving revision 1.106
diff -p -u -r1.106 scan-gram.l
--- src/scan-gram.l     21 Oct 2006 10:03:35 -0000      1.106
+++ src/scan-gram.l     3 Nov 2006 10:05:49 -0000
@@ -523,7 +523,7 @@ splice       (\\[ \f\t\v]*\n)*
       {
        STRING_FINISH;
        loc->start = code_start;
-       val->chars = last_string;
+       val->nonconst_chars = last_string;
        BEGIN INITIAL;
        return BRACED_CODE;
       }
@@ -537,7 +537,7 @@ splice       (\\[ \f\t\v]*\n)*
     unexpected_eof (code_start, "}");
     STRING_FINISH;
     loc->start = code_start;
-    val->chars = last_string;
+    val->nonconst_chars = last_string;
     BEGIN INITIAL;
     return BRACED_CODE;
   }
Index: tests/Makefile.am
===================================================================
RCS file: /sources/bison/bison/tests/Makefile.am,v
retrieving revision 1.42
diff -p -u -r1.42 Makefile.am
--- tests/Makefile.am   6 Mar 2006 08:29:22 -0000       1.42
+++ tests/Makefile.am   3 Nov 2006 10:05:49 -0000
@@ -88,6 +88,7 @@ maintainer-check-posix: $(TESTSUITE)
 .PHONY: maintainer-check-valgrind
 maintainer-check-valgrind: $(TESTSUITE)
        test -z '$(VALGRIND)' || \
+          VALGRIND_OPTS='--leak-check=full --show-reachable=yes' \
           $(TESTSUITE) PREBISON='$(VALGRIND) -q' PREPARSER='$(VALGRIND) -q'
 
 .PHONY: maintainer-check
Index: tests/calc.at
===================================================================
RCS file: /sources/bison/bison/tests/calc.at,v
retrieving revision 1.92
diff -p -u -r1.92 calc.at
--- tests/calc.at       15 Sep 2006 15:56:26 -0000      1.92
+++ tests/calc.at       3 Nov 2006 10:05:49 -0000
@@ -337,6 +337,7 @@ main (int argc, const char **argv)
 ]AT_SKEL_CC_IF([], [m4_bmatch([$4], [%debug],
 [  yydebug = 1;])])[
   status = yyparse (]AT_PARAM_IF([&result, &count])[);
+  fclose (input);
   if (global_result != result)
     abort ();
   if (global_count != count)
Index: tests/testsuite.at
===================================================================
RCS file: /sources/bison/bison/tests/testsuite.at,v
retrieving revision 1.28
diff -p -u -r1.28 testsuite.at
--- tests/testsuite.at  14 May 2005 06:49:48 -0000      1.28
+++ tests/testsuite.at  3 Nov 2006 10:05:50 -0000
@@ -19,6 +19,14 @@
 # 02110-1301, USA.
 
 
+# Bison often leaks memory when its exit status is non-zero, so set
+# --leak-check=summary for Valgrind in that case.
+m4_pushdef([ORIGINAL_AT_CHECK], m4_defn([AT_CHECK]))
+m4_pushdef([AT_CHECK],
+[ORIGINAL_AT_CHECK(m4_if(m4_quote(m4_substr(m4_quote($1), 0, 5)), [bison],
+                         m4_if([$2], [0], [], [], [],
+                               [[VALGRIND_OPTS="$VALGRIND_OPTS 
--leak-check=summary --show-reachable=no" ]]))$@)])
+
 # Testing resistance to user bugs.
 m4_include([input.at])
 
@@ -64,3 +72,6 @@ m4_include([c++.at])
 m4_include([cxx-type.at])
 # Regression tests
 m4_include([glr-regression.at])
+
+m4_popdef([AT_CHECK])
+m4_popdef([ORIGINAL_AT_CHECK])
Index: gnulib/lib/quotearg.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/quotearg.c,v
retrieving revision 1.51
diff -p -u -r1.51 quotearg.c
--- gnulib/lib/quotearg.c       31 Oct 2006 21:51:45 -0000      1.51
+++ gnulib/lib/quotearg.c       3 Nov 2006 10:05:51 -0000
@@ -590,6 +590,17 @@ quotearg_n_options (int n, char const *a
   static struct slotvec *slotvec = &slotvec0;
   struct slotvec *sv = slotvec;
 
+  if (arg == NULL)
+    {
+      unsigned int i;
+      for (i = 0; i < nslots; i += 1)
+        if (slotvec[i].val != slot0)
+          free (slotvec[i].val);
+      if (slotvec != &slotvec0)
+        free (slotvec);
+      return NULL;
+    }
+
   if (n < 0)
     abort ();
 
@@ -689,3 +700,9 @@ quotearg_colon (char const *arg)
 {
   return quotearg_char (arg, ':');
 }
+
+void
+quotearg_free (void)
+{
+  quotearg_n_options (0, NULL, 0, NULL);
+}
Index: gnulib/lib/quotearg.h
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/quotearg.h,v
retrieving revision 1.12
diff -p -u -r1.12 quotearg.h
--- gnulib/lib/quotearg.h       14 May 2005 06:03:58 -0000      1.12
+++ gnulib/lib/quotearg.h       3 Nov 2006 10:05:51 -0000
@@ -134,4 +134,7 @@ char *quotearg_char (char const *arg, ch
 /* Equivalent to quotearg_char (ARG, ':').  */
 char *quotearg_colon (char const *arg);
 
+/* Free any allocated memory.  */
+void quotearg_free (void);
+
 #endif /* !QUOTEARG_H_ */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]