[PATCH v3 07/15] perf python: Check counts_values size in set_values

From: Ian Rogers

Date: Sun Aug 09 2026 - 03:15:39 EST


The set_values function incorrectly assumed the list contained exactly
5 elements. Add a check to prevent out-of-bounds access.

Fixes: 877108e42b1b ("perf tools: Initial python binding")
Signed-off-by: Ian Rogers <irogers@xxxxxxxxxx>
---
tools/perf/util/python.c | 38 ++++++++++++++++++++++++++++++--------
1 file changed, 30 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index c7ae1f85aec6..f64d662bd3ee 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -1881,11 +1881,11 @@ static void pyrf_counts_values__delete(struct pyrf_counts_values *pcounts_values
0, help }

static PyMemberDef pyrf_counts_values_members[] = {
- counts_values_member_def(val, T_ULONG, "Value of event"),
- counts_values_member_def(ena, T_ULONG, "Time for which enabled"),
- counts_values_member_def(run, T_ULONG, "Time for which running"),
- counts_values_member_def(id, T_ULONG, "Unique ID for an event"),
- counts_values_member_def(lost, T_ULONG, "Num of lost samples"),
+ counts_values_member_def(val, T_ULONGLONG, "Value of event"),
+ counts_values_member_def(ena, T_ULONGLONG, "Time for which enabled"),
+ counts_values_member_def(run, T_ULONGLONG, "Time for which running"),
+ counts_values_member_def(id, T_ULONGLONG, "Unique ID for an event"),
+ counts_values_member_def(lost, T_ULONGLONG, "Num of lost samples"),
{ .name = NULL, },
};

@@ -1895,8 +1895,15 @@ static PyObject *pyrf_counts_values_get_values(struct pyrf_counts_values *self,

if (!vals)
return NULL;
- for (int i = 0; i < 5; i++)
- PyList_SetItem(vals, i, PyLong_FromLong(self->values.values[i]));
+ for (int i = 0; i < 5; i++) {
+ PyObject *val = PyLong_FromUnsignedLongLong(self->values.values[i]);
+
+ if (!val) {
+ Py_DECREF(vals);
+ return NULL;
+ }
+ PyList_SetItem(vals, i, val);
+ }

return vals;
}
@@ -1907,19 +1914,34 @@ static int pyrf_counts_values_set_values(struct pyrf_counts_values *self, PyObje
Py_ssize_t size;
PyObject *item = NULL;

+ if (list == NULL) {
+ PyErr_SetString(PyExc_TypeError, "cannot delete attribute");
+ return -1;
+ }
+
if (!PyList_Check(list)) {
PyErr_SetString(PyExc_TypeError, "Value assigned must be a list");
return -1;
}

size = PyList_Size(list);
+ if (size != 5) {
+ PyErr_SetString(PyExc_ValueError, "List must have exactly 5 entries");
+ return -1;
+ }
+
for (Py_ssize_t i = 0; i < size; i++) {
+ unsigned long long val;
+
item = PyList_GetItem(list, i);
if (!PyLong_Check(item)) {
PyErr_SetString(PyExc_TypeError, "List members should be numbers");
return -1;
}
- self->values.values[i] = PyLong_AsLong(item);
+ val = PyLong_AsUnsignedLongLong(item);
+ if (val == (unsigned long long)-1 && PyErr_Occurred())
+ return -1;
+ self->values.values[i] = val;
}

return 0;
--
2.55.0.679.g6767b8d81c-goog