]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
getopt: fix memory leaks and integer overflows [ASAN & valgrind]
authorSami Kerola <kerolasa@iki.fi>
Mon, 14 Mar 2016 21:06:30 +0000 (21:06 +0000)
committerSami Kerola <kerolasa@iki.fi>
Wed, 20 Apr 2016 21:04:34 +0000 (22:04 +0100)
The getopt(1) is short living command, and one could argue ensuring all
allocations are freed at end of execution is waste of time.  There is a
point in that, but making test-suite runs to be less noisy with ASAN is also
nice as it encourages reading the errors when/if they happen.

Reviewed-by: Yuriy M. Kaminskiy <yumkam@gmail.com>
Reviewed-by: Karel Zak <kzak@redhat.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
misc-utils/getopt.c

index 2cff2eb85e5a89fbfa51da6d1ca780a24acc470c..dc2a976df71541dfc265bcfef7c99d712f98c5db 100644 (file)
@@ -86,6 +86,7 @@ struct getopt_control {
        int long_options_length;        /* length of options array */
        int long_options_nr;            /* number of used elements in array */
        unsigned int
+               free_name:1,            /* free up argv[0] after printout */
                compatible:1,           /* compatibility mode for 'difficult' programs */
                quiet_errors:1,         /* print errors */
                quiet_output:1,         /* print output */
@@ -181,7 +182,7 @@ static void print_normalized(const struct getopt_control *ctl, const char *arg)
  * optstr must contain the short options, and longopts the long options.
  * Other settings are found in global variables.
  */
-static int generate_output(const struct getopt_control *ctl, char *argv[], int argc)
+static int generate_output(struct getopt_control *ctl, char *argv[], int argc)
 {
        int exit_code = EXIT_SUCCESS;   /* Assume everything will be OK */
        int opt;
@@ -195,8 +196,10 @@ static int generate_output(const struct getopt_control *ctl, char *argv[], int a
        optind = 0;
 
        while ((opt =
-               (getopt_long_fp(argc, argv, ctl->optstr, ctl->long_options, &longindex)))
-              != EOF)
+               (getopt_long_fp
+                (argc, argv, ctl->optstr,
+                 (const struct option *)ctl->long_options, &longindex)))
+              != EOF) {
                if (opt == '?' || opt == ':')
                        exit_code = GETOPT_EXIT_CODE;
                else if (!ctl->quiet_output) {
@@ -216,13 +219,19 @@ static int generate_output(const struct getopt_control *ctl, char *argv[], int a
                                        print_normalized(ctl, optarg ? optarg : "");
                        }
                }
-
+       }
        if (!ctl->quiet_output) {
                printf(" --");
                while (optind < argc)
                        print_normalized(ctl, argv[optind++]);
                printf("\n");
        }
+       for (longindex = 0; longindex < ctl->long_options_nr; longindex++)
+               free((char *)ctl->long_options[longindex].name);
+       free(ctl->long_options);
+       free(ctl->optstr);
+       if (ctl->free_name)
+               free(argv[0]);
        return exit_code;
 }
 
@@ -373,9 +382,6 @@ int main(int argc, char *argv[])
        textdomain(PACKAGE);
        atexit(close_stdout);
 
-       add_longopt(&ctl, NULL, 0);     /* init */
-       getopt_long_fp = getopt_long;
-
        if (getenv("GETOPT_COMPATIBLE"))
                ctl.compatible = 1;
 
@@ -391,6 +397,9 @@ int main(int argc, char *argv[])
                        parse_error(_("missing optstring argument"));
        }
 
+       add_longopt(&ctl, NULL, 0);     /* init */
+       getopt_long_fp = getopt_long;
+
        if (argv[1][0] != '-' || ctl.compatible) {
                ctl.quote = 0;
                ctl.optstr = xmalloc(strlen(argv[1]) + 1);
@@ -417,6 +426,7 @@ int main(int argc, char *argv[])
                case 'n':
                        free(name);
                        name = xstrdup(optarg);
+                       ctl.free_name = 1;
                        break;
                case 'q':
                        ctl.quiet_errors = 1;
@@ -428,6 +438,7 @@ int main(int argc, char *argv[])
                        ctl.shell = shell_type(optarg);
                        break;
                case 'T':
+                       free(ctl.long_options);
                        return TEST_EXIT_CODE;
                case 'u':
                        ctl.quote = 0;