diff options
| author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2026-06-06 11:25:40 -0300 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2026-06-06 14:42:19 -0300 |
| commit | 33fa2bf5608fc36bc25231592145f4738f14f11b (patch) | |
| tree | 807ce00d95a4bd33b69181127ec677ea1128a619 | |
| parent | e2496db45bfd8dfb6154ec415798fee330f1cc0a (diff) | |
| download | linux-33fa2bf5608fc36bc25231592145f4738f14f11b.tar.gz linux-33fa2bf5608fc36bc25231592145f4738f14f11b.zip | |
perf tools: Fix int16_t truncation of max_cpu_num in set_max_cpu_num()
set_max_cpu_num() assigns the sysfs "possible" CPU count to
max_cpu_num.cpu which is int16_t (struct perf_cpu). On systems
with >32767 possible CPUs the value silently truncates, potentially
wrapping negative. This causes cpunode_map to be underallocated
and subsequent cpu__get_node() calls to read out of bounds.
The matching check for max_present_cpu_num was added by commit
c760174401f6 ("perf cpumap: Reduce cpu size from int to int16_t")
but max_cpu_num was missed. Add the same INT16_MAX guard.
Fixes: c760174401f605cf ("perf cpumap: Reduce cpu size from int to int16_t")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Ian Rogers <irogers@google.com>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
| -rw-r--r-- | tools/perf/util/cpumap.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index d3432622b2ad..21fa781b03cc 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -494,6 +494,16 @@ static void set_max_cpu_num(void) if (ret) goto out; + /* + * struct perf_cpu.cpu is int16_t (libperf ABI) — clamp to avoid + * truncation to negative. See tools/lib/perf/TODO for the ABI + * widening plan. + */ + if (max > INT16_MAX) { + pr_warning("WARNING: max possible cpus %d exceeds int16_t, clamping to %d\n", + max, INT16_MAX); + max = INT16_MAX; + } max_cpu_num.cpu = max; /* get the highest present cpu number for a sparse allocation */ @@ -506,11 +516,12 @@ static void set_max_cpu_num(void) ret = get_max_num(path, &max); if (!ret && max > INT16_MAX) { - pr_err("Read out of bounds max cpus of %d\n", max); - ret = -1; + pr_warning("WARNING: max present cpus %d exceeds int16_t, clamping to %d\n", + max, INT16_MAX); + max = INT16_MAX; } if (!ret) - max_present_cpu_num.cpu = (int16_t)max; + max_present_cpu_num.cpu = max; out: if (ret) pr_err("Failed to read max cpus, using default of %d\n", max_cpu_num.cpu); @@ -647,7 +658,9 @@ int cpu__setup_cpunode_map(void) while ((dent2 = readdir(dir2)) != NULL) { if (dent2->d_type != DT_LNK || sscanf(dent2->d_name, "cpu%u", &cpu) < 1) continue; - cpunode_map[cpu] = mem; + /* cpunode_map allocated for max_cpu_num entries */ + if (cpu < (unsigned int)max_cpu_num.cpu) + cpunode_map[cpu] = mem; } closedir(dir2); } |
