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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox