From nobody Sun Dec 14 12:13:03 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 179FD1BCA07; Wed, 12 Mar 2025 16:07:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741795631; cv=none; b=RyIUCSXVJzax4rPVXXpRfErWKSFLQGl4MzlbMo/IkuQBg27jx807lwte6fLpoQEHYW/SmkmeI2qYdrqBFxw4xohDPvBI5PDjSWiVIDbOkUEO6piy7MAUHLqrYE7c+fkgQMWc/jhUx+UpNk/691TLQ6L24ziJPdxCg0LtnO+HU6Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741795631; c=relaxed/simple; bh=46xRCXWbIBHRCLTqqyMeJZ3nLxdD2D7kjeMKxw12v6Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=l3IfmiIH26Zm4nsFsag8cCwXsmWyXVnSvYIMM7iMPi6jeIVy9cnH66Pmy6yHnMuLeuHFNGFsD6bLASUzL9csXSxYbUrUAJp2oGxFpitSfc/VOQ5PJel5xWCgziNmA3tbGQyc0kxRXYDsI+1u2War46axg4bYXNTBWTUSh9UG8i8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PPNZ4Tad; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="PPNZ4Tad" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 86B74C4CEED; Wed, 12 Mar 2025 16:07:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1741795629; bh=46xRCXWbIBHRCLTqqyMeJZ3nLxdD2D7kjeMKxw12v6Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PPNZ4TadNVfsXB82RIm1gm4dpfBefTbk/K0O1O2NumEKg0XOFF0CWJydijQpz+nHU X/R15ghDpWmXmlozmfZs4HfmB1iSFN3tRTTK2LbGn1dR42tKeyVYpL9b5ec8+7raK7 r9eLvD4YALZ6fOOjkx7f5W+7ruJc1GksI/aqqgPl1w8k36J3jxhTQtFQPPp1Q7SiD1 7kO8eQEG9MYmfIU6y4JLuN4NwA0lIdfJWypc0W414v4Ku7VGUlSJo92YzHqpBtmIgE mjgGmR7Hs63A3VZCTMQRQwzLo7A7JUkTEiH0UMBBLAxNvT72NL3c9Nelz20YCAsFJZ UpG4cT67QshBQ== From: Arnaldo Carvalho de Melo To: Namhyung Kim Cc: Ingo Molnar , Thomas Gleixner , James Clark , Jiri Olsa , Ian Rogers , Adrian Hunter , Kan Liang , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Arnaldo Carvalho de Melo Subject: [PATCH 3/3] perf python: Don't keep a raw_data pointer to consumed ring buffer space Date: Wed, 12 Mar 2025 13:06:51 -0300 Message-ID: <20250312160651.280817-4-acme@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250312160651.280817-1-acme@kernel.org> References: <20250312160651.280817-1-acme@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Arnaldo Carvalho de Melo When processing tracepoints the perf python binding was parsing the event before calling perf_mmap__consume(&md->core) in pyrf_evlist__read_on_cpu(). But part of this event parsing was to set the perf_sample->raw_data pointer to the payload of the event, which then could be overwritten by other event before tracepoint fields were asked for via event.prev_comm in a python program, for instance. This also happened with other fields, but strings were were problems were surfacing, as there is UTF-8 validation for the potentially garbled data. This ended up showing up as (with some added debugging messages): ( field 'prev_comm' ret=3D0x7f7c31f65110, raw_size=3D68 ) ( field 'prev_= pid' ret=3D0x7f7c23b1bed0, raw_size=3D68 ) ( field 'prev_prio' ret=3D0x7f7= c239c0030, raw_size=3D68 ) ( field 'prev_state' ret=3D0x7f7c239c0250, raw_= size=3D68 ) time 14771421785867 prev_comm=3D prev_pid=3D1919907691 prev_pri= o=3D796026219 prev_state=3D0x303a32313175 =3D=3D> ( XXX '=EF=BF=BD=EF=BF=BD' len=3D16, raw_size=3D68) ( field 'next_comm' = ret=3D(nil), raw_size=3D68 ) Traceback (most recent call last): File "/home/acme/git/perf-tools-next/tools/perf/python/tracepoint.py", l= ine 51, in main() File "/home/acme/git/perf-tools-next/tools/perf/python/tracepoint.py", l= ine 46, in main event.next_comm, ^^^^^^^^^^^^^^^ AttributeError: 'perf.sample_event' object has no attribute 'next_comm' When event.next_comm was asked for, the PyUnicode_FromString() python API would fail and that tracepoint field wouldn't be available, stopping the tools/perf/python/tracepoint.py test tool. So if the event is a tracepoint, copy the raw_data before consuming the ring buffer for the event. This is similar to what was done in e8968e654191390a ("perf python: Fix pyrf_evlist__read_on_cpu event consuming"), but wasn't when adding support for tracepoints in bae57e3825a3dded ("perf python: Add support to resolve tracepoint fields"), fix it. Fixes: bae57e3825a3dded ("perf python: Add support to resolve tracepoint fi= elds") Cc: Adrian Hunter Cc: Ian Rogers Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/python.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index f9491b6699764fbc..e1bd8143296385fc 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #ifdef HAVE_LIBTRACEEVENT #include @@ -38,9 +39,16 @@ struct pyrf_event { PyObject_HEAD struct evsel *evsel; struct perf_sample sample; + /** @raw_data_copy: read_on_cpu consumes rb, may be overwritten at get_tr= acepoint_field */ + void *raw_data_copy; union perf_event event; }; =20 +static void pyrf_event__delete(struct pyrf_event *pevent) +{ + zfree(&pevent->raw_data_copy); +} + #define sample_members \ sample_member_def(sample_ip, ip, T_ULONGLONG, "event ip"), \ sample_member_def(sample_pid, pid, T_INT, "event pid"), \ @@ -94,6 +102,7 @@ static PyTypeObject pyrf_mmap_event__type =3D { .tp_doc =3D pyrf_mmap_event__doc, .tp_members =3D pyrf_mmap_event__members, .tp_repr =3D (reprfunc)pyrf_mmap_event__repr, + .tp_dealloc =3D (destructor)pyrf_event__delete, }; =20 static const char pyrf_task_event__doc[] =3D PyDoc_STR("perf task (fork/ex= it) event object."); @@ -129,6 +138,7 @@ static PyTypeObject pyrf_task_event__type =3D { .tp_doc =3D pyrf_task_event__doc, .tp_members =3D pyrf_task_event__members, .tp_repr =3D (reprfunc)pyrf_task_event__repr, + .tp_dealloc =3D (destructor)pyrf_event__delete, }; =20 static const char pyrf_comm_event__doc[] =3D PyDoc_STR("perf comm event ob= ject."); @@ -158,6 +168,7 @@ static PyTypeObject pyrf_comm_event__type =3D { .tp_doc =3D pyrf_comm_event__doc, .tp_members =3D pyrf_comm_event__members, .tp_repr =3D (reprfunc)pyrf_comm_event__repr, + .tp_dealloc =3D (destructor)pyrf_event__delete, }; =20 static const char pyrf_throttle_event__doc[] =3D PyDoc_STR("perf throttle = event object."); @@ -190,6 +201,7 @@ static PyTypeObject pyrf_throttle_event__type =3D { .tp_doc =3D pyrf_throttle_event__doc, .tp_members =3D pyrf_throttle_event__members, .tp_repr =3D (reprfunc)pyrf_throttle_event__repr, + .tp_dealloc =3D (destructor)pyrf_event__delete, }; =20 static const char pyrf_lost_event__doc[] =3D PyDoc_STR("perf lost event ob= ject."); @@ -225,6 +237,7 @@ static PyTypeObject pyrf_lost_event__type =3D { .tp_doc =3D pyrf_lost_event__doc, .tp_members =3D pyrf_lost_event__members, .tp_repr =3D (reprfunc)pyrf_lost_event__repr, + .tp_dealloc =3D (destructor)pyrf_event__delete, }; =20 static const char pyrf_read_event__doc[] =3D PyDoc_STR("perf read event ob= ject."); @@ -255,6 +268,7 @@ static PyTypeObject pyrf_read_event__type =3D { .tp_doc =3D pyrf_read_event__doc, .tp_members =3D pyrf_read_event__members, .tp_repr =3D (reprfunc)pyrf_read_event__repr, + .tp_dealloc =3D (destructor)pyrf_event__delete, }; =20 static const char pyrf_sample_event__doc[] =3D PyDoc_STR("perf sample even= t object."); @@ -295,11 +309,14 @@ static PyObject* tracepoint_field(const struct pyrf_event *pe, struct tep_format_field *fie= ld) { struct tep_handle *pevent =3D field->event->tep; - void *data =3D pe->sample.raw_data; + void *data =3D pe->raw_data_copy; PyObject *ret =3D NULL; unsigned long long val; unsigned int offset, len; =20 + if (data =3D=3D NULL) + return ret; + if (field->flags & TEP_FIELD_IS_ARRAY) { offset =3D field->offset; len =3D field->size; @@ -346,6 +363,11 @@ get_tracepoint_field(struct pyrf_event *pevent, PyObje= ct *attr_name) field =3D tep_find_any_field(tp_format, str); return field ? tracepoint_field(pevent, field) : NULL; } +#else // HAVE_LIBTRACEEVENT +static bool is_tracepoint(const struct pyrf_event *pevent __maybe_unused) +{ + return false; +} #endif /* HAVE_LIBTRACEEVENT */ =20 static PyObject* @@ -369,6 +391,7 @@ static PyTypeObject pyrf_sample_event__type =3D { .tp_doc =3D pyrf_sample_event__doc, .tp_members =3D pyrf_sample_event__members, .tp_repr =3D (reprfunc)pyrf_sample_event__repr, + .tp_dealloc =3D (destructor)pyrf_event__delete, .tp_getattro =3D (getattrofunc) pyrf_sample_event__getattro, }; =20 @@ -407,6 +430,7 @@ static PyTypeObject pyrf_context_switch_event__type =3D= { .tp_doc =3D pyrf_context_switch_event__doc, .tp_members =3D pyrf_context_switch_event__members, .tp_repr =3D (reprfunc)pyrf_context_switch_event__repr, + .tp_dealloc =3D (destructor)pyrf_event__delete, }; =20 static int pyrf_event__setup_types(void) @@ -478,8 +502,10 @@ static PyObject *pyrf_event__new(const union perf_even= t *event) =20 ptype =3D pyrf_event__type[event->header.type]; pevent =3D PyObject_New(struct pyrf_event, ptype); - if (pevent !=3D NULL) + if (pevent !=3D NULL) { memcpy(&pevent->event, event, event->header.size); + pevent->raw_data_copy =3D NULL; + } return (PyObject *)pevent; } =20 @@ -1020,6 +1046,14 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyr= f_evlist *pevlist, =20 err =3D evsel__parse_sample(evsel, event, &pevent->sample); =20 + if (is_tracepoint(pevent) && + pevent->sample.raw_size > 0 && !pevent->raw_data_copy) { + // No need to check here, only when get_tracepoint_field gets + // called, if ever, then it can fail getting the value for + // a tracepoint field. + pevent->raw_data_copy =3D memdup(pevent->sample.raw_data, pevent->sampl= e.raw_size); + } + /* Consume the even only after we parsed it out. */ perf_mmap__consume(&md->core); =20 --=20 2.48.1