From 054d1c7717b95d9089cd3b80e9e85fe1f2ea0471 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:40 -0700 Subject: perf python: Handle Py_None for thread and cpu maps The python stubs allow passing None for threads and cpus to the perf.parse_events() and perf.parse_metrics() bindings. However, PyArg_ParseTuple parses None into a Py_None object, which is not a NULL pointer. Because the C code lacked an explicit check for Py_None, it would cast Py_None to a pyrf_thread_map/pyrf_cpu_map struct pointer and dereference it, causing a memory corruption crash. Fix this pre-existing issue by explicitly checking for Py_None alongside NULL in pyrf__parse_events, pyrf__parse_metrics, and pyrf_evsel__open. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/python.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'tools/perf/util/python.c') diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 3a9f4e35d0bb..4ec5a91d45c0 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -2091,10 +2091,10 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, &pcpus, &pthreads, &group, &inherit)) return NULL; - if (pthreads != NULL) + if (pthreads != NULL && pthreads != Py_None) threads = ((struct pyrf_thread_map *)pthreads)->threads; - if (pcpus != NULL) + if (pcpus != NULL && pcpus != Py_None) cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; evsel->core.attr.inherit = inherit; @@ -3341,8 +3341,10 @@ static PyObject *pyrf__parse_events(PyObject *self, PyObject *args) return NULL; } - threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL; - cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL; + threads = (pthreads && pthreads != Py_None) ? + ((struct pyrf_thread_map *)pthreads)->threads : NULL; + cpus = (pcpus && pcpus != Py_None) ? + ((struct pyrf_cpu_map *)pcpus)->cpus : NULL; parse_events_error__init(&err); perf_evlist__set_maps(evlist__core(evlist), cpus, threads); @@ -3375,8 +3377,10 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args) return NULL; } - threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL; - cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL; + threads = (pthreads && pthreads != Py_None) ? + ((struct pyrf_thread_map *)pthreads)->threads : NULL; + cpus = (pcpus && pcpus != Py_None) ? + ((struct pyrf_cpu_map *)pcpus)->cpus : NULL; perf_evlist__set_maps(evlist__core(evlist), cpus, threads); ret = metricgroup__parse_groups(evlist, pmu ?: "all", input, -- cgit