From df92d94c758a39ac1c9e15e95ffa3afce6db68ea Mon Sep 17 00:00:00 2001 From: Michael Abbott Date: Tue, 12 Mar 2024 10:41:31 +0000 Subject: [PATCH 1/3] Fix conversion of ctypes pointers passed to C extension As reported in issue #153 there appears to be a problem in converting a Python integer generated by ctypes.address() back to a void* pointer when naively using PyArg_ParseTuple. Don't fully understand why this issue arises, but the fix is straightforward. Fixes issue #153 --- softioc/extension.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/softioc/extension.c b/softioc/extension.c index fd71687c..d14feac0 100644 --- a/softioc/extension.c +++ b/softioc/extension.c @@ -98,9 +98,12 @@ static PyObject *db_put_field(PyObject *self, PyObject *args) { const char *name; short dbrType; - void *pbuffer; + PyObject *buffer_ptr; long length; - if (!PyArg_ParseTuple(args, "shnl", &name, &dbrType, &pbuffer, &length)) + if (!PyArg_ParseTuple(args, "shOl", &name, &dbrType, &buffer_ptr, &length)) + return NULL; + void *pbuffer = PyLong_AsVoidPtr(buffer_ptr); + if (!pbuffer) return NULL; struct dbAddr dbAddr; @@ -133,9 +136,12 @@ static PyObject *db_get_field(PyObject *self, PyObject *args) { const char *name; short dbrType; - void *pbuffer; + PyObject *buffer_ptr; long length; - if (!PyArg_ParseTuple(args, "shnl", &name, &dbrType, &pbuffer, &length)) + if (!PyArg_ParseTuple(args, "shOl", &name, &dbrType, &buffer_ptr, &length)) + return NULL; + void *pbuffer = PyLong_AsVoidPtr(buffer_ptr); + if (!pbuffer) return NULL; struct dbAddr dbAddr; From 57790d4760aa38eae2f74a4ae75f97dbb966b8a0 Mon Sep 17 00:00:00 2001 From: Michael Abbott Date: Tue, 12 Mar 2024 10:42:50 +0000 Subject: [PATCH 2/3] Wrap comment going over 80 column limit --- softioc/extension.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/softioc/extension.c b/softioc/extension.c index d14feac0..08b33616 100644 --- a/softioc/extension.c +++ b/softioc/extension.c @@ -113,11 +113,11 @@ static PyObject *db_put_field(PyObject *self, PyObject *args) long put_result; /* There are two important locks to consider at this point: The Global - * Interpreter Lock (GIL) and the EPICS record lock. A deadlock is possible if - * this thread holds the GIL and wants the record lock (which happens inside - * dbPutField), and there exists another EPICS thread that has the record lock - * and wants to call Python (which requires the GIL). - * This can occur if this code is called as part of an asynchronous on_update + * Interpreter Lock (GIL) and the EPICS record lock. A deadlock is possible + * if this thread holds the GIL and wants the record lock (which happens + * inside dbPutField), and there exists another EPICS thread that has the + * record lock and wants to call Python (which requires the GIL). This can + * occur if this code is called as part of an asynchronous on_update * callback. * Therefore, we must ensure we relinquish the GIL while we perform this * EPICS call, to avoid potential deadlocks. From d55483d0ad9c5546fca167941fe593097264676d Mon Sep 17 00:00:00 2001 From: Michael Abbott Date: Tue, 12 Mar 2024 11:21:05 +0000 Subject: [PATCH 3/3] Update change log --- CHANGELOG.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a835ad00..0a52e959 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,6 +10,10 @@ Versioning `_. Unreleased_ ----------- +Fixed: + +- `Fix conversion of ctypes pointers passed to C extension <../../pull/154>`_ + 4.5.0_ - 2023-12-04 -------------------