From: sashiko-bot@kernel.org
To: "Leo Yan" <leo.yan@arm.com>
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [PATCH 2/4] perf: Assemble split thread maps in script and stat report
Date: Sun, 15 Nov 2026 13:56:32 +0000 [thread overview]
Message-ID: <sashiko-outbox-215548@kernel.org> (raw)
In-Reply-To: <20261115-perf_fix_large_threads-v1-2-69c9b86b9ae5@arm.com>
Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [Medium] perf: NULL dereference on incomplete thread map when
set_maps() is deferred
- [Low] perf stat: leak of perf_stat.threads and perf_stat.cpus in
__cmd_report()
It also noticed 1 related pre-existing issue this patch does not
introduce:
- [Medium] perf stat: memory leaks of session, evlist, and maps in
__cmd_report() [1]
--
commit 296ec71892d6fd09202f3090775a27df449bf978
Author: Leo Yan <leo.yan@arm.com>
perf: Assemble split thread maps in script and stat report
This commit adds thread_map__append_event() to assemble split
PERF_RECORD_THREAD_MAP records in perf script and perf stat report before
publishing the completed thread map to the evlist and allocating stats.
> diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
> index b6691ebb1b4ef..e41925fb86b8d 100644
> --- a/tools/perf/builtin-script.c
> +++ b/tools/perf/builtin-script.c
[ ... ]
> @@ -3416,6 +3417,10 @@ static int __cmd_script(struct perf_script *script)
> }
>
> ret = perf_session__process_events(script->session);
> + if (!ret && !session_done() && script->threads_is_appending) {
> + pr_err("Incomplete thread map: missing final record.\n");
> + ret = -EINVAL;
> + }
>
> if (script->per_event_dump)
> perf_script__exit_per_event_dump_stats(script);
> @@ -3975,6 +3980,10 @@ static int set_maps(struct perf_script *script)
> {
> struct evlist *evlist = script->session->evlist;
>
> + /* Appending can move the map, so share it only after the final record. */
> + if (script->threads_is_appending)
> + return 0;
> +
> if (!script->cpus || !script->threads)
> return 0;
[Severity: Medium]
Can deferring set_maps() while threads_is_appending is true cause a NULL
pointer dereference in perf_counts() when the final PERF_RECORD_THREAD_MAP
record is missing?
If a PERF_RECORD_THREAD_MAP record with PERF_RECORD_MISC_THREAD_MAP_MORE set
is followed by PERF_RECORD_CPU_MAP and stat events without the final thread
map record, set_maps() returns early and skips perf_evlist__set_maps() and
evlist__alloc_stats(), leaving counter->counts NULL on each evsel. Because
threads_is_appending is only checked after perf_session__process_events()
returns, subsequent PERF_RECORD_STAT_ROUND or PERF_RECORD_STAT events are
processed first: process_stat_round_event() -> perf_stat_process_counter() ->
process_counter_maps() calls perf_counts(counter->counts, idx, thread) and
dereferences NULL, or perf_event__process_stat_event() fails earlier with an
"Invalid CPU -1" error that masks the incomplete thread map message. The
same regression affects set_maps() and __cmd_report() in
tools/perf/builtin-stat.c.
> diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
> index 37752d6bfef45..19d120b647065 100644
> --- a/tools/perf/builtin-stat.c
> +++ b/tools/perf/builtin-stat.c
[ ... ]
> @@ -2301,15 +2306,19 @@ int process_thread_map_event(const struct perf_tool *tool,
> union perf_event *event)
> {
> struct perf_stat *st = container_of(tool, struct perf_stat, tool);
> + int ret;
>
> - if (st->threads) {
> + if (st->threads && !st->threads_is_appending) {
> pr_warning("Extra thread map event, ignoring.\n");
> return 0;
> }
>
> - st->threads = thread_map__new_event(&event->thread_map);
> - if (!st->threads)
> - return -ENOMEM;
> + ret = thread_map__append_event(&st->threads, &event->thread_map);
> + if (ret)
> + return ret;
> +
> + st->threads_is_appending =
> + event->header.misc & PERF_RECORD_MISC_THREAD_MAP_MORE;
>
> return set_maps(st);
> }
[Severity: Low]
Does this leak st->threads when thread_map__append_event() fails partway
through or when the final thread map record is missing?
thread_map__append_event() stores the allocated map in st->threads before
duplicating the comm strings, and set_maps() keeps st->threads private while
st->threads_is_appending is true. Unlike cmd_script(), which calls
perf_script__exit() to release script->threads and script->cpus,
__cmd_report() only calls perf_session__delete(session) and never calls
perf_thread_map__put(perf_stat.threads).
> @@ -2405,11 +2414,13 @@ static int __cmd_report(int argc, const char **argv)
> evsel_list = session->evlist;
>
> ret = perf_session__process_events(session);
> - if (ret)
> - return ret;
> + if (!ret && !session_done() && perf_stat.threads_is_appending) {
> + pr_err("Incomplete thread map: missing final record.\n");
> + ret = -EINVAL;
> + }
>
> perf_session__delete(session);
> - return 0;
> + return ret;
> }
[Severity: Medium]
This problem wasn't introduced by this patch, but does __cmd_report() leak
perf_stat.threads, perf_stat.cpus, evsel_list, and the aggregation maps
[1]?
cmd_stat() allocates evsel_list with evlist__new() and returns directly from
__cmd_report(), bypassing the cleanup at the end of cmd_stat(). If
perf_session__new() fails in __cmd_report(), returning early before
evlist__put(evsel_list) leaks the initial evsel_list. During event
processing, set_maps() passes perf_stat.cpus and perf_stat.threads to
perf_evlist__set_maps(), which takes an extra reference on each map, and
process_stat_config_event() allocates aggregation maps;perf_session__delete()
only drops session->evlist's references and __cmd_report() never drops
perf_stat.threads, perf_stat.cpus, or the aggregation maps via
perf_stat__exit_aggr_mode().
[1] https://sashiko.dev/#/bug/linux-b77574e3-cc57-4338-8810-73a0cfa6fff7
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261115-perf_fix_large_threads-v1-0-69c9b86b9ae5@arm.com?part=2
next prev parent reply other threads:[~2026-11-15 13:56 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-15 13:34 [PATCH 0/4] perf: Support thread maps larger than one record Leo Yan
2026-11-15 13:34 ` [PATCH 1/4] perf synthetic-events: Split oversized thread maps into records Leo Yan
2026-11-15 13:46 ` sashiko-bot
2026-11-15 13:34 ` [PATCH 2/4] perf: Assemble split thread maps in script and stat report Leo Yan
2026-11-15 13:56 ` sashiko-bot [this message]
2026-11-15 13:34 ` [PATCH 3/4] perf test: Cover multi-record thread map synthesis Leo Yan
2026-11-15 13:40 ` sashiko-bot
2026-11-15 13:34 ` [PATCH 4/4] perf docs: Describe multi-record thread maps Leo Yan
2026-11-15 13:41 ` 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=sashiko-outbox-215548@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=leo.yan@arm.com \
--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;
as well as URLs for NNTP newsgroup(s).