From: sashiko-bot@kernel.org
To: "Arnaldo Carvalho de Melo" <acme@kernel.org>
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [PATCH 5/8] perf sched: Clean up idle_threads entry on init failure
Date: Fri, 05 Jun 2026 20:53:09 +0000 [thread overview]
Message-ID: <20260605205309.810BA1F00893@smtp.kernel.org> (raw)
In-Reply-To: <20260605203316.1758661-6-acme@kernel.org>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
Pre-existing issues:
- [High] Negative array index out-of-bounds read and write in `get_idle_thread()` due to unchecked `sample->cpu`.
- [Medium] Missing `thread__put()` causes reference count and handle leaks for both `idle` and `thread` variables in `timehist_get_thread()`.
- [Medium] A NULL pointer dereference occurs in `latency_runtime_event()` if thread allocation fails.
- [Medium] Leaked `callchain_cursor_node` structs inside `idle_thread_runtime` when the thread is destroyed.
--
commit f4d6b1c97697918976cf8390fa17c92e7ead50bf
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf sched: Clean up idle_threads entry on init failure
get_idle_thread() allocates a thread via thread__new() and stores it in
idle_threads[cpu], then calls init_idle_thread() to set up the private
data. If init_idle_thread() fails, the partially initialized thread is
left in idle_threads[cpu], causing subsequent calls to return a thread
without private data. This patch resets the slot on init failure.
> diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
> index 555247568e7a6..e47db1c5c6020 100644
> --- a/tools/perf/builtin-sched.c
> +++ b/tools/perf/builtin-sched.c
> @@ -2475,8 +2475,11 @@ static struct thread *get_idle_thread(int cpu)
[Severity: High]
This is a pre-existing issue, but does this function properly validate the
cpu index? The sample->cpu field is read from the untrusted perf.data file.
If a sample lacks a CPU, it typically defaults to (u32)-1. When passed to
get_idle_thread() as an int, cpu becomes -1.
The upper-bounds check will evaluate to false:
if ((cpu >= idle_max_cpu) || (idle_threads == NULL)) {
And then a negative index is used to read and write memory out of bounds:
if (idle_threads[cpu] == NULL) {
idle_threads[cpu] = thread__new(0, 0);
Could this unchecked value lead to heap metadata corruption?
> idle_threads[cpu] = thread__new(0, 0);
>
> if (idle_threads[cpu]) {
> - if (init_idle_thread(idle_threads[cpu]) < 0)
> + if (init_idle_thread(idle_threads[cpu]) < 0) {
> + /* clean up so next call doesn't find a half-initialized thread */
> + thread__zput(idle_threads[cpu]);
> return NULL;
> + }
> }
> }
[Severity: Medium]
This isn't a bug introduced by this patch, but doesn't the
timehist_get_thread() function leak the thread and idle references on error
paths?
tools/perf/builtin-sched.c:timehist_get_thread() {
...
idle = get_idle_thread(sample->cpu);
if (idle == NULL) {
...
}
itr = thread__priv(idle);
if (itr == NULL)
return NULL;
...
}
It appears get_idle_thread() returns a reference to the idle thread that is
never released with thread__put(). Also, returning NULL when itr is NULL
leaks both the newly acquired idle thread and the primary thread reference.
Could this cause a memory leak over time during large traces?
[Severity: Medium]
This is a pre-existing issue, but does latency_runtime_event() dereference
a potentially NULL thread pointer before checking it?
tools/perf/builtin-sched.c:latency_runtime_event() {
...
struct thread *thread = machine__findnew_thread(machine, -1, pid);
struct work_atoms *atoms = thread_atoms_search(&sched->atom_root,
thread, &sched->cmp_pid);
...
if (thread == NULL)
return -1;
...
}
If thread allocation fails, machine__findnew_thread() returns NULL, which is
then passed to thread_atoms_search() and dereferenced before the check
if (thread == NULL) is reached. Is it possible to move the NULL check above
the call to thread_atoms_search()?
[Severity: Medium]
This isn't a bug introduced by this patch, but does the idle_thread_runtime
structure permanently leak its callchain_cursor nodes?
When init_idle_thread() sets up the idle thread:
tools/perf/builtin-sched.c:init_idle_thread() {
...
callchain_cursor_reset(&itr->cursor);
thread__set_priv(thread, itr);
...
}
During execution, save_idle_callchain() allocates nodes dynamically via
callchain_cursor__copy(). However, the destructor for thread private data is
typically just free(), meaning the dynamically allocated callchain_cursor_node
elements within itr->cursor are never deep-freed when the idle thread is
destroyed. Should a proper destructor be registered to free these nodes?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260605203316.1758661-1-acme@kernel.org?part=5
next prev parent reply other threads:[~2026-06-05 20:53 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-05 20:33 [PATCHES v1 0/8] perf tools: Fix OOB writes, refcount bugs, and BUG_ON in mmap/stat/c2c/sched Arnaldo Carvalho de Melo
2026-06-05 20:33 ` [PATCH 1/8] perf mmap: Guard cpu__get_node() return in aio_bind() Arnaldo Carvalho de Melo
2026-06-05 20:48 ` sashiko-bot
2026-06-05 20:33 ` [PATCH 2/8] perf stat: Bounds-check CPU index in topology aggregation callbacks Arnaldo Carvalho de Melo
2026-06-05 20:33 ` [PATCH 3/8] perf c2c: Bounds-check CPU and node IDs before bitmap and array access Arnaldo Carvalho de Melo
2026-06-05 20:46 ` sashiko-bot
2026-06-05 20:33 ` [PATCH 4/8] perf c2c: Bounds-check CPU IDs in setup_nodes() topology loop Arnaldo Carvalho de Melo
2026-06-05 20:33 ` [PATCH 5/8] perf sched: Clean up idle_threads entry on init failure Arnaldo Carvalho de Melo
2026-06-05 20:53 ` sashiko-bot [this message]
2026-06-05 20:33 ` [PATCH 6/8] perf sched: Fix thread reference leak in idle hist processing Arnaldo Carvalho de Melo
2026-06-05 20:46 ` sashiko-bot
2026-06-05 20:33 ` [PATCH 7/8] perf sched: Use thread__put() in free_idle_threads() Arnaldo Carvalho de Melo
2026-06-05 20:49 ` sashiko-bot
2026-06-05 20:33 ` [PATCH 8/8] perf sched: Replace BUG_ON and add NULL checks in replay event helpers Arnaldo Carvalho de Melo
2026-06-05 20:46 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260605205309.810BA1F00893@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=acme@kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.