summaryrefslogtreecommitdiffstats
path: root/misc-utils/getopt.c
diff options
context:
space:
mode:
authorSami Kerola2016-03-14 22:06:30 +0100
committerSami Kerola2016-04-20 23:04:34 +0200
commitb13fedd485cb2e9663c1c69a5cb8c512f9ad4771 (patch)
tree765dce8179b88c0677a9866747ac861ecab2e40f /misc-utils/getopt.c
parentlib: avoid double free in loopdev.c (diff)
downloadkernel-qcow2-util-linux-b13fedd485cb2e9663c1c69a5cb8c512f9ad4771.tar.gz
kernel-qcow2-util-linux-b13fedd485cb2e9663c1c69a5cb8c512f9ad4771.tar.xz
kernel-qcow2-util-linux-b13fedd485cb2e9663c1c69a5cb8c512f9ad4771.zip
getopt: fix memory leaks and integer overflows [ASAN & valgrind]
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>
Diffstat (limited to 'misc-utils/getopt.c')
-rw-r--r--misc-utils/getopt.c25
1 files changed, 18 insertions, 7 deletions
diff --git a/misc-utils/getopt.c b/misc-utils/getopt.c
index 2cff2eb85..dc2a976df 100644
--- a/misc-utils/getopt.c
+++ b/misc-utils/getopt.c
@@ -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;