Hi!

The memory leaks in the options handling, while they perhaps aren't that
big, keep cluttering valgrind --leak-check=full outputs and make it harder
to find other, more severe, bugs.

The following patch attempts to fix that by allocating strings which we want
to keep allocated forever, and from time to time lose all the pointers
pointing to them, in an obstack.  That could in theory make the allocations
tiny bit faster, but more importantly all the memory is reachable at exit
and thus valgrind doesn't complain about those.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2013-02-26  Jakub Jelinek  <ja...@redhat.com>

        * opts.h: Include obstack.h.
        (opts_concat): New prototype.
        (opts_obstack): New declaration.
        * opts.c (opts_concat): New function.
        (opts_obstack): New variable.
        (init_options_struct): Call gcc_init_obstack on opts_obstack.
        (finish_options): Use opts_concat instead of concat
        and XOBNEWVEC instead of XNEWVEC.
        * opts-common.c (generate_canonical_option, decode_cmdline_option,
        generate_option): Likewise.
        * Makefile.in (OPTS_H): Depend on $(OBSTACK_H).
        * lto-wrapper.c (main): Call gcc_init_obstack on opts_obstack.

--- gcc/opts.h.jj       2013-01-11 09:02:48.000000000 +0100
+++ gcc/opts.h  2013-02-26 14:08:32.956457725 +0100
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.
 
 #include "input.h"
 #include "vec.h"
+#include "obstack.h"
 
 /* Specifies how a switch's VAR_VALUE relates to its FLAG_VAR.  */
 enum cl_var_type {
@@ -304,6 +305,12 @@ extern const char **in_fnames;
 
 extern unsigned num_in_fnames;
 
+extern char *opts_concat (const char *first, ...);
+
+/* Obstack for option strings.  */
+
+extern struct obstack opts_obstack;
+
 size_t find_opt (const char *input, unsigned int lang_mask);
 extern int integral_argument (const char *arg);
 extern bool enum_value_to_arg (const struct cl_enum_arg *enum_args,
--- gcc/opts.c.jj       2013-02-15 16:30:01.000000000 +0100
+++ gcc/opts.c  2013-02-26 14:13:14.939802328 +0100
@@ -268,6 +268,40 @@ add_comma_separated_to_vector (void **pv
   *pvec = v;
 }
 
+/* Like libiberty concat, but allocate using opts_obstack.  */
+
+char *
+opts_concat (const char *first, ...)
+{
+  char *newstr, *end;
+  size_t length = 0;
+  const char *arg;
+  va_list ap;
+
+  /* First compute the size of the result and get sufficient memory.  */
+  va_start (ap, first);
+  for (arg = first; arg; arg = va_arg (ap, const char *))
+    length += strlen (arg);
+  newstr = XOBNEWVEC (&opts_obstack, char, length + 1);
+  va_end (ap);
+
+  /* Now copy the individual pieces to the result string. */
+  va_start (ap, first);
+  for (arg = first, end = newstr; arg; arg = va_arg (ap, const char *))
+    {
+      length = strlen (arg);
+      memcpy (end, arg, length);
+      end += length;
+    }
+  *end = '\0';
+  va_end (ap);
+  return newstr;
+}
+
+/* Obstack for option strings.  */
+
+struct obstack opts_obstack;
+
 /* Initialize OPTS and OPTS_SET before using them in parsing options.  */
 
 void
@@ -275,6 +309,8 @@ init_options_struct (struct gcc_options
 {
   size_t num_params = get_num_compiler_params ();
 
+  gcc_obstack_init (&opts_obstack);
+
   *opts = global_options_init;
   memset (opts_set, 0, sizeof (*opts_set));
 
@@ -638,8 +674,8 @@ finish_options (struct gcc_options *opts
         directory, typically the directory to contain the object
         file.  */
       if (opts->x_dump_dir_name)
-       opts->x_dump_base_name = concat (opts->x_dump_dir_name,
-                                        opts->x_dump_base_name, NULL);
+       opts->x_dump_base_name = opts_concat (opts->x_dump_dir_name,
+                                             opts->x_dump_base_name, NULL);
       else if (opts->x_aux_base_name
               && strcmp (opts->x_aux_base_name, HOST_BIT_BUCKET) != 0)
        {
@@ -649,8 +685,9 @@ finish_options (struct gcc_options *opts
          if (opts->x_aux_base_name != aux_base)
            {
              int dir_len = aux_base - opts->x_aux_base_name;
-             char *new_dump_base_name =
-               XNEWVEC (char, strlen (opts->x_dump_base_name) + dir_len + 1);
+             char *new_dump_base_name
+               = XOBNEWVEC (&opts_obstack, char,
+                            strlen (opts->x_dump_base_name) + dir_len + 1);
 
              /* Copy directory component from OPTS->X_AUX_BASE_NAME.  */
              memcpy (new_dump_base_name, opts->x_aux_base_name, dir_len);
--- gcc/opts-common.c.jj        2013-01-11 09:02:28.000000000 +0100
+++ gcc/opts-common.c   2013-02-26 14:11:14.834505092 +0100
@@ -276,7 +276,7 @@ generate_canonical_option (size_t opt_in
       && !option->cl_reject_negative
       && (opt_text[1] == 'W' || opt_text[1] == 'f' || opt_text[1] == 'm'))
     {
-      char *t = XNEWVEC (char, option->opt_len + 5);
+      char *t = XOBNEWVEC (&opts_obstack, char, option->opt_len + 5);
       t[0] = '-';
       t[1] = opt_text[1];
       t[2] = 'n';
@@ -301,11 +301,9 @@ generate_canonical_option (size_t opt_in
       else
        {
          gcc_assert (option->flags & CL_JOINED);
-         decoded->canonical_option[0] = concat (opt_text, arg, NULL);
+         decoded->canonical_option[0] = opts_concat (opt_text, arg, NULL);
          decoded->canonical_option[1] = NULL;
          decoded->canonical_option_num_elements = 1;
-         if (opt_text != option->opt_text)
-           free (CONST_CAST (char *, opt_text));
        }
     }
   else
@@ -590,7 +588,7 @@ decode_cmdline_option (const char **argv
     {
       size_t j;
       size_t len = strlen (arg);
-      char *arg_lower = XNEWVEC (char, len + 1);
+      char *arg_lower = XOBNEWVEC (&opts_obstack, char, len + 1);
 
       for (j = 0; j < len; j++)
        arg_lower[j] = TOLOWER ((unsigned char) arg[j]);
@@ -670,7 +668,8 @@ decode_cmdline_option (const char **argv
          decoded->canonical_option_num_elements = result;
        }
     }
-  decoded->orig_option_with_args_text = p = XNEWVEC (char, total_len);
+  decoded->orig_option_with_args_text
+    = p = XOBNEWVEC (&opts_obstack, char, total_len);
   for (i = 0; i < result; i++)
     {
       size_t len = strlen (argv[i]);
@@ -932,8 +931,8 @@ generate_option (size_t opt_index, const
 
     case 2:
       decoded->orig_option_with_args_text
-       = concat (decoded->canonical_option[0], " ",
-                 decoded->canonical_option[1], NULL);
+       = opts_concat (decoded->canonical_option[0], " ",
+                      decoded->canonical_option[1], NULL);
       break;
 
     default:
--- gcc/Makefile.in.jj  2013-02-20 18:40:49.000000000 +0100
+++ gcc/Makefile.in     2013-02-20 18:40:49.000000000 +0100
@@ -919,7 +919,7 @@ PREDICT_H = predict.h predict.def
 CPPLIB_H = $(srcdir)/../libcpp/include/line-map.h \
        $(srcdir)/../libcpp/include/cpplib.h
 INPUT_H = $(srcdir)/../libcpp/include/line-map.h input.h
-OPTS_H = $(INPUT_H) $(VEC_H) opts.h
+OPTS_H = $(INPUT_H) $(VEC_H) opts.h $(OBSTACK_H)
 DECNUM_H = $(DECNUM)/decContext.h $(DECNUM)/decDPD.h $(DECNUM)/decNumber.h \
        $(DECNUMFMT)/decimal32.h $(DECNUMFMT)/decimal64.h \
        $(DECNUMFMT)/decimal128.h $(DECNUMFMT)/decimal128Local.h
--- gcc/lto-wrapper.c.jj        2013-01-11 16:15:52.000000000 +0100
+++ gcc/lto-wrapper.c   2013-02-26 20:12:14.339926950 +0100
@@ -915,6 +915,8 @@ main (int argc, char *argv[])
 {
   const char *p;
 
+  gcc_obstack_init (&opts_obstack);
+
   p = argv[0] + strlen (argv[0]);
   while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
     --p;

        Jakub

Reply via email to