[PATCH 1/1] libtracecmd: fix memory leak on partial reverse iteration

Felix Moessbauer <[email protected]> Fri, 21 Nov 2025 14:47:49 +0100
Newsgroups org.kernel.vger.linux-trace-devel
Message-ID <[email protected]>
When calling tracecmd_iterate_events_reverse with a callback that does
not always return 0, the trace is only partially iterated. By that, the
non-iterated records are leaked, resulting in the error:

 1 pages still allocated on cpu <cpu>

We fix this by always iterating the remaining events on all selected
CPUs. In the full iteration case, this stops on the first record as this
is already zero. In the partial iteration case, all remaining records
are freed, which is - by construction of the records list - at max a
page size.

Signed-off-by: Felix Moessbauer <[email protected]>
---
Note, that this bug has been reported in [1].

[1] https://lore.kernel.org/linux-trace-devel/[email protected]/

Best regards,
Felix Moessbauer
Siemens AG

 lib/trace-cmd/trace-input.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c
index f2471c92..afdbd2aa 100644
--- a/lib/trace-cmd/trace-input.c
+++ b/lib/trace-cmd/trace-input.c
@@ -2995,6 +2995,25 @@ static struct tep_record *next_last_event(struct tracecmd_input *handle,
 	return record;
 }
 
+static void free_last_events(struct tracecmd_input *handle,
+			     struct tep_record **last_records,
+			     cpu_set_t *cpu_set, int cpu_size,
+			     int cpus)
+{
+	struct tep_record *record;
+	int cpu;
+
+	for (cpu = 0; cpu < cpus; cpu++) {
+		if (cpus && !CPU_ISSET_S(cpu, cpu_size, cpu_set))
+			continue;
+
+		do {
+			record = next_last_event(handle, last_records, cpu);
+			tracecmd_free_record(record);
+		} while (record);
+	}
+}
+
 /**
  * tracecmd_iterate_events_reverse - iterate events over a given handle backwards
  * @handle: The handle to iterate over
@@ -3057,6 +3076,7 @@ int tracecmd_iterate_events_reverse(struct tracecmd_input *handle,
 		}
 	} while (next_cpu >= 0 && ret == 0);
 
+	free_last_events(handle, records, cpus, cpu_size, max_cpus);
 	free(records);
 
 	return ret;
-- 
2.51.0