]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
perf c2c: Fix hist entry and format list leaks in c2c_he_free()
authorArnaldo Carvalho de Melo <acme@redhat.com>
Sat, 13 Jun 2026 18:16:42 +0000 (15:16 -0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 17 Jun 2026 12:21:03 +0000 (09:21 -0300)
c2c_he_free() calls hists__delete_entries() which only walks the
output-sorted entries tree.  During c2c resort, when cacheline entries
are merged and the redundant entry is freed, the inner hists have not
been output-resorted yet, so hists->entries is empty.  The actual inner
hist_entry objects live in entries_in_array[] and entries_collapsed,
which are never walked, leaking all inner hist_entry objects for every
merged cacheline.

Additionally, the dynamically allocated format entries on hists->list
are never unregistered or freed.

Fix both issues by switching to hists__delete_all_entries() which walks
all rb_root trees, and calling perf_hpp__reset_output_field() to clean
up format entries.

Fixes: bf0e0d407ea09ce5 ("perf c2c report: Add sample processing")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-c2c.c
tools/perf/util/hist.c
tools/perf/util/hist.h

index eabb922ef295ef86dde1904d9f04813ac32e807b..c9584dbedf77afe84b2ab93c9bf459bc6e4a590c 100644 (file)
@@ -184,7 +184,7 @@ static void c2c_he_free(void *he)
 
        c2c_he = container_of(he, struct c2c_hist_entry, he);
        if (c2c_he->hists) {
-               hists__delete_entries(&c2c_he->hists->hists);
+               hists__delete_all_entries(&c2c_he->hists->hists);
                perf_hpp__reset_output_field(&c2c_he->hists->list);
                zfree(&c2c_he->hists);
        }
index df978c996b6c22626405ea317d15841ab6810afa..c93915625ee75de1ecd5809ffcca13217d261b40 100644 (file)
@@ -3041,7 +3041,7 @@ static void hists__delete_remaining_entries(struct rb_root_cached *root)
        }
 }
 
-static void hists__delete_all_entries(struct hists *hists)
+void hists__delete_all_entries(struct hists *hists)
 {
        hists__delete_entries(hists);
        hists__delete_remaining_entries(&hists->entries_in_array[0]);
index 8fb89d81ef069d95454d0830ad88b8b7851aac6a..b830cbe7f95bf597fa88c7937cb399379676ebc7 100644 (file)
@@ -391,6 +391,7 @@ int hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
 
 void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
 void hists__delete_entries(struct hists *hists);
+void hists__delete_all_entries(struct hists *hists);
 void hists__output_recalc_col_len(struct hists *hists, int max_rows);
 
 struct hist_entry *hists__get_entry(struct hists *hists, int idx);