From: Rusty Russell Date: Tue, 22 Mar 2011 01:19:36 +0000 (+1030) Subject: opt: fix memory leak in tests. X-Git-Url: http://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=6fa62e5ae1e29646aa718e99020fdf2efee74373;ds=sidebyside opt: fix memory leak in tests. No only does this give us one more ccanlint point, it clears the way to see if we introduce a *real* memory leak later. --- diff --git a/ccan/opt/test/run-correct-reporting.c b/ccan/opt/test/run-correct-reporting.c index 4f775a29..8534f291 100644 --- a/ccan/opt/test/run-correct-reporting.c +++ b/ccan/opt/test/run-correct-reporting.c @@ -42,6 +42,8 @@ int main(int argc, char *argv[]) free(err_output); err_output = NULL; + /* parse_args allocates argv */ + free(argv); return exit_status(); } diff --git a/ccan/opt/test/run-helpers.c b/ccan/opt/test/run-helpers.c index 081d27a9..a58e4d91 100644 --- a/ccan/opt/test/run-helpers.c +++ b/ccan/opt/test/run-helpers.c @@ -19,6 +19,9 @@ static int saved_fprintf(FILE *ignored, const char *fmt, ...); #define vfprintf(f, fmt, ap) saved_vprintf(fmt, ap) static int saved_vprintf(const char *fmt, va_list ap); +#define malloc(size) saved_malloc(size) +static void *saved_malloc(size_t size); + #include #include #include @@ -69,6 +72,13 @@ static int saved_fprintf(FILE *ignored, const char *fmt, ...) return ret; } +#undef malloc +static void *last_allocation; +static void *saved_malloc(size_t size) +{ + return last_allocation = malloc(size); +} + /* Test helpers. */ int main(int argc, char *argv[]) { @@ -220,15 +230,25 @@ int main(int argc, char *argv[]) reset_options(); opt_register_noarg("-a", opt_version_and_exit, "1.2.3", ""); + /* parse_args allocates argv */ + free(argv); + + argc = 2; + argv = malloc(sizeof(argv[0]) * 3); + argv[0] = "thisprog"; + argv[1] = "-a"; + argv[2] = NULL; + exitval = setjmp(exited); if (exitval == 0) { - parse_args(&argc, &argv, "-a", NULL); + opt_parse(&argc, argv, save_err_output); fail("opt_show_version_and_exit returned?"); } else { ok1(exitval - 1 == 0); } ok1(strcmp(output, "1.2.3\n") == 0); free(output); + free(argv); output = NULL; } @@ -238,9 +258,16 @@ int main(int argc, char *argv[]) reset_options(); opt_register_noarg("-a", opt_usage_and_exit, "[args]", ""); + + argc = 2; + argv = malloc(sizeof(argv[0]) * 3); + argv[0] = "thisprog"; + argv[1] = "-a"; + argv[2] = NULL; + exitval = setjmp(exited); if (exitval == 0) { - parse_args(&argc, &argv, "-a", NULL); + opt_parse(&argc, argv, save_err_output); fail("opt_usage_and_exit returned?"); } else { ok1(exitval - 1 == 0); @@ -249,6 +276,9 @@ int main(int argc, char *argv[]) ok1(strstr(output, argv[0])); ok1(strstr(output, "[-a]")); free(output); + free(argv); + /* It exits without freeing usage string. */ + free(last_allocation); output = NULL; } @@ -377,6 +407,7 @@ int main(int argc, char *argv[]) ok1(!strcmp(output, "thisprog: --garbage: unrecognized option\n")); free(output); + free(argv); output = NULL; } @@ -386,18 +417,19 @@ int main(int argc, char *argv[]) reset_options(); opt_register_noarg("-a", opt_usage_and_exit, "[args]", ""); + argc = 2; + argv = malloc(sizeof(argv[0]) * 3); + argv[0] = "thisprog"; + argv[1] = "--garbage"; + argv[2] = NULL; exitval = setjmp(exited); if (exitval == 0) { - argc = 2; - argv = malloc(sizeof(argv[0]) * 3); - argv[0] = "thisprog"; - argv[1] = "--garbage"; - argv[2] = NULL; opt_parse(&argc, argv, opt_log_stderr_exit); fail("opt_log_stderr_exit returned?"); } else { ok1(exitval - 1 == 1); } + free(argv); ok1(!strcmp(output, "thisprog: --garbage: unrecognized option\n")); free(output); diff --git a/ccan/opt/test/run-no-options.c b/ccan/opt/test/run-no-options.c index 5ae2dd35..cf255fee 100644 --- a/ccan/opt/test/run-no-options.c +++ b/ccan/opt/test/run-no-options.c @@ -25,6 +25,9 @@ int main(int argc, char *argv[]) ok1(strcmp(argv[1], "extra") == 0); ok1(strcmp(argv[2], "args") == 0); + /* parse_args allocates argv */ + free(argv); + return exit_status(); } diff --git a/ccan/opt/test/run-usage.c b/ccan/opt/test/run-usage.c index 73e6a949..2af2c7ee 100644 --- a/ccan/opt/test/run-usage.c +++ b/ccan/opt/test/run-usage.c @@ -106,5 +106,7 @@ int main(int argc, char *argv[]) ok1(strstr(output, "AAAAll")); free(output); + free(shortname); + free(longname); return exit_status(); } diff --git a/ccan/opt/test/run.c b/ccan/opt/test/run.c index 8982baa0..9a769bad 100644 --- a/ccan/opt/test/run.c +++ b/ccan/opt/test/run.c @@ -291,5 +291,7 @@ int main(int argc, char *argv[]) ok1(strcmp(argv[4], "-a") == 0); ok1(!argv[5]); + /* parse_args allocates argv */ + free(argv); return exit_status(); } diff --git a/ccan/opt/test/utils.c b/ccan/opt/test/utils.c index fa0a2022..9544fa77 100644 --- a/ccan/opt/test/utils.c +++ b/ccan/opt/test/utils.c @@ -29,7 +29,7 @@ void show_arg(char buf[OPT_SHOW_LEN], const char *arg) char *err_output = NULL; -static void save_err_output(const char *fmt, ...) +void save_err_output(const char *fmt, ...) { va_list ap; char *p; @@ -49,7 +49,8 @@ static void save_err_output(const char *fmt, ...) err_output = p; } -/* FIXME: This leaks, BTW. */ +static bool allocated = false; + bool parse_args(int *argc, char ***argv, ...) { char **a; @@ -63,7 +64,12 @@ bool parse_args(int *argc, char ***argv, ...) (*argc)++; a = realloc(a, sizeof(*a) * (*argc + 1)); } + + if (allocated) + free(*argv); + *argv = a; + allocated = true; /* Re-set before parsing. */ optind = 0; diff --git a/ccan/opt/test/utils.h b/ccan/opt/test/utils.h index b5192f7c..f7c18967 100644 --- a/ccan/opt/test/utils.h +++ b/ccan/opt/test/utils.h @@ -5,6 +5,7 @@ bool parse_args(int *argc, char ***argv, ...); extern char *err_output; +void save_err_output(const char *fmt, ...); extern unsigned int test_cb_called; char *test_noarg(void *arg);