Re: [PATCH v1 13/58] perf python: Use evsel in sample in pyrf_event

sashiko-bot
2026-04-20T00:46:14Z

Sashiko AI review found 2 potential issue(s):
- [Critical] Uninitialized memory dereference and memory corruption on error path.
- [High] Unbalanced reference count leads to Use-After-Free of evsel.
--

commit 9f11b0fde656e141e642877371cb83e3963c35bd
Author: Ian Rogers <irogers@google.com>

perf python: Use evsel in sample in pyrf_event

Avoid a duplicated evsel by using the one in sample.

> diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
> --- a/tools/perf/util/python.c
> +++ b/tools/perf/util/python.c
[ ... ]
> @@ -274,7 +273,7 @@ static PyMemberDef pyrf_sample_event__members[] = {
>
> static void pyrf_sample_event__delete(struct pyrf_event *pevent)
> {
> - evsel__put(pevent->evsel);
> + evsel__put(pevent->sample.evsel);

This isn't a regression from this patch, but does pyrf_evlist__read_on_cpu()
take ownership of the evsel reference?

Looking at pyrf_evlist__read_on_cpu(), the evsel is retrieved using
evlist__event2evsel(), which returns a borrowed reference. However, this
destructor unconditionally calls evsel__put().

Since no evsel__get() is called when the python event is created, will every
garbage-collected sample event erroneously decrement the evsel's internal
refcount, potentially leading to a use-after-free while the evsel is still
actively used by the evlist?

> perf_sample__exit(&pevent->sample);
> Py_TYPE(pevent)->tp_free((PyObject*)pevent);
> }
[ ... ]
> @@ -1770,8 +1769,6 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
> return Py_None;
> }
>
> evsel = evlist__event2evsel(evlist, event);
> if (!evsel) {
> Py_DECREF(pyevent);

This isn't a regression introduced by this patch, but are we at risk of an
uninitialized memory dereference on this error path?

When a new pyrf_event is allocated with PyObject_New(), the embedded sample
struct is uninitialized. If evlist__event2evsel() returns NULL, this error
path calls Py_DECREF(pyevent).

This triggers the destructor pyrf_sample_event__delete(), which calls
evsel__put(pevent->sample.evsel) and perf_sample__exit(&pevent->sample).

Because pevent->sample was never initialized, could this pass uninitialized
heap garbage to evsel__put() and perf_sample__exit(), potentially causing
memory corruption?

> Py_INCREF(Py_None);
> return Py_None;
> }
>
> - pevent->evsel = evsel;
> -
> perf_mmap__consume(&md->core);
>
> err = evsel__parse_sample(evsel, &pevent->event, &pevent->sample);

--
Sashiko AI review · https://sashiko.dev/#/patchset/20260419235911.2186050-1-irogers@google.com?part=13