]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
perf sched: Fix thread reference leaks in timehist_get_thread()
authorArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 4 Jun 2026 21:18:05 +0000 (18:18 -0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 4 Jun 2026 22:17:36 +0000 (19:17 -0300)
timehist_get_thread() acquires a thread reference via
machine__findnew_thread() and an idle thread reference via
get_idle_thread() (which calls thread__get()).  Two error paths in
the idle_hist block return NULL without releasing these references:

 - When get_idle_thread() fails, the thread reference leaks.
 - When thread__priv(idle) returns NULL, both idle and thread leak.

Additionally, the idle thread reference acquired on the success path
is never released, leaking a reference on every sample when
--idle-hist is active.

Add thread__put() calls on both error paths and release the idle
reference after use on the success path.

Fixes: 5d8f17fb5822 ("perf sched timehist: Add -I/--idle-hist option")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-sched.c

index 4aa7833cae6e36b8a07583621115d26ec3fa9155..7bd61028327b39db945b2be56b4588888f4262ca 100644 (file)
@@ -2546,12 +2546,16 @@ static struct thread *timehist_get_thread(struct perf_sched *sched,
                        idle = get_idle_thread(sample->cpu);
                        if (idle == NULL) {
                                pr_err("Failed to get idle thread for cpu %d.\n", sample->cpu);
+                               thread__put(thread);
                                return NULL;
                        }
 
                        itr = thread__priv(idle);
-                       if (itr == NULL)
+                       if (itr == NULL) {
+                               thread__put(idle);
+                               thread__put(thread);
                                return NULL;
+                       }
 
                        thread__put(itr->last_thread);
                        itr->last_thread = thread__get(thread);
@@ -2559,6 +2563,8 @@ static struct thread *timehist_get_thread(struct perf_sched *sched,
                        /* copy task callchain when entering to idle */
                        if (perf_sample__intval(sample, "next_pid") == 0)
                                save_idle_callchain(sched, itr, sample);
+
+                       thread__put(idle);
                }
        }