[PATCH 05/31] pahole: Fix instance memory leak on early returns in prototype__stdio_fprintf_value
Arnaldo Carvalho de Melo <[email protected]> Wed, 29 Jul 2026 16:07:05 -0300
| Newsgroups | org.kernel.vger.dwarves,org.kernel.vger.bpf |
|---|---|
| Message-ID | <[email protected]> |
From: Arnaldo Carvalho de Melo <[email protected]> prototype__stdio_fprintf_value() allocates an instance buffer via malloc() but has 14 early return statements between the allocation and the free(instance) at the out: label. None of these early returns free instance, leaking memory on every error path during --prettify binary record processing. Change all bare returns after the successful malloc to 'goto out', setting printed to the error value before jumping. The out: label already does free(instance) and return printed. The return -ENOMEM when instance == NULL (malloc failure) is kept as-is since there is nothing to free. Fixes: fdfc64ec44f4ad53 ("pahole: Introduce --range") Assisted-by: Claude:claude-sonnet-4-5 Signed-off-by: Arnaldo Carvalho de Melo <[email protected]> --- pahole.c | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/pahole.c b/pahole.c index 390d5f2dd20e4dfd..0096dfa34e5047c8 100644 --- a/pahole.c +++ b/pahole.c @@ -2584,9 +2584,9 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty return -ENOMEM; if (type__instance_read_once(header, input) < 0) { - int err = --errno; + printed = --errno; fprintf(stderr, "pahole: --header (%s) type couldn't be read\n", conf.header_type); - return err; + goto out; } if (conf.range || prototype->range) { @@ -2598,14 +2598,16 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty fprintf(stderr, "pahole: --header_type=%s not found\n", conf.header_type); else fprintf(stderr, "pahole: range (%s) requires --header\n", range); - return -ESRCH; + printed = -ESRCH; + goto out; } char *member_name = NULL; if (asprintf(&member_name, "%s.%s", range, "offset") == -1) { fprintf(stderr, "pahole: not enough memory for range=%s\n", range); - return -ENOMEM; + printed = -ENOMEM; + goto out; } int64_t value = type_instance__int_value(header, member_name); @@ -2614,7 +2616,8 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty fprintf(stderr, "pahole: couldn't read the '%s' member of '%s' for evaluating range=%s\n", member_name, conf.header_type, range); free(member_name); - return -ESRCH; + printed = -ESRCH; + goto out; } seek_bytes = value; @@ -2628,7 +2631,8 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty if (seek_bytes < total_read_bytes) { fprintf(stderr, "pahole: can't go back in input, already read %" PRIu64 " bytes, can't go to position %#" PRIx64 "\n", total_read_bytes, seek_bytes); - return -ENOMEM; + printed = -ENOMEM; + goto out; } if (global_verbose) { @@ -2640,7 +2644,8 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty if (asprintf(&member_name, "%s.%s", range, "size") == -1) { fprintf(stderr, "pahole: not enough memory for range=%s\n", range); - return -ENOMEM; + printed = -ENOMEM; + goto out; } value = type_instance__int_value(header, member_name); @@ -2649,7 +2654,8 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty fprintf(stderr, "pahole: couldn't read the '%s' member of '%s' for evaluating range=%s\n", member_name, conf.header_type, range); free(member_name); - return -ESRCH; + printed = -ESRCH; + goto out; } size_bytes = value; @@ -2661,9 +2667,9 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty free(member_name); if (pipe_seek(input, seek_bytes) < 0) { - int err = --errno; + printed = --errno; fprintf(stderr, "Couldn't --seek_bytes %s (%" PRIu64 "\n", conf.seek_bytes, seek_bytes); - return err; + goto out; } goto do_read; @@ -2676,7 +2682,8 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty if (!header) { fprintf(stderr, "pahole: --seek_bytes (%s) makes reference to --header but it wasn't specified\n", conf.seek_bytes); - return -ESRCH; + printed = -ESRCH; + goto out; } const char *member_name = conf.seek_bytes + sizeof("$header.") - 1; @@ -2684,7 +2691,8 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty if (value < 0) { fprintf(stderr, "pahole: couldn't read the '%s' member of '%s' for evaluating --seek_bytes=%s\n", member_name, conf.header_type, conf.seek_bytes); - return -ESRCH; + printed = -ESRCH; + goto out; } seek_bytes = value; @@ -2696,7 +2704,8 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty if (seek_bytes < header->type->size) { fprintf(stderr, "pahole: seek bytes evaluated from --seek_bytes=%s is less than the header type size\n", conf.seek_bytes); - return -EINVAL; + printed = -EINVAL; + goto out; } } else { seek_bytes = strtol(conf.seek_bytes, NULL, 0); @@ -2709,9 +2718,9 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty } if (pipe_seek(input, seek_bytes) < 0) { - int err = --errno; + printed = --errno; fprintf(stderr, "Couldn't --seek_bytes %s (%" PRIu64 "\n", conf.seek_bytes, seek_bytes); - return err; + goto out; } } @@ -2720,7 +2729,8 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty if (!header) { fprintf(stderr, "pahole: --size_bytes (%s) makes reference to --header but it wasn't specified\n", conf.size_bytes); - return -ESRCH; + printed = -ESRCH; + goto out; } const char *member_name = conf.size_bytes + sizeof("$header.") - 1; @@ -2728,7 +2738,8 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty if (value < 0) { fprintf(stderr, "pahole: couldn't read the '%s' member of '%s' for evaluating --size_bytes=%s\n", member_name, conf.header_type, conf.size_bytes); - return -ESRCH; + printed = -ESRCH; + goto out; } size_bytes = value; -- 2.55.0