https://github.com/python/cpython/commit/6e91d1f9aafc6e375092b8c14f6e30ebc74e4004
commit: 6e91d1f9aafc6e375092b8c14f6e30ebc74e4004
branch: main
author: Peter Bierma <zintensity...@gmail.com>
committer: vstinner <vstin...@python.org>
date: 2025-04-02T17:04:25+02:00
summary:

gh-131974: Fix usages of `locked_deref` in `ctypes` (#131975)

files:
A Misc/NEWS.d/next/Library/2025-04-01-09-20-32.gh-issue-131974.AIzshA.rst
M Modules/_ctypes/_ctypes.c

diff --git 
a/Misc/NEWS.d/next/Library/2025-04-01-09-20-32.gh-issue-131974.AIzshA.rst 
b/Misc/NEWS.d/next/Library/2025-04-01-09-20-32.gh-issue-131974.AIzshA.rst
new file mode 100644
index 00000000000000..abf2f54f8c2035
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-04-01-09-20-32.gh-issue-131974.AIzshA.rst
@@ -0,0 +1,2 @@
+Fix several thread-safety issues in :mod:`ctypes` on the :term:`free
+threaded <free threading>` build.
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 59ea579627e56f..efefc0157237bd 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -5326,13 +5326,13 @@ static PyType_Spec pycsimple_spec = {
   PyCPointer_Type
 */
 static PyObject *
-Pointer_item(PyObject *myself, Py_ssize_t index)
+Pointer_item_lock_held(PyObject *myself, Py_ssize_t index)
 {
     CDataObject *self = _CDataObject_CAST(myself);
     Py_ssize_t size;
     Py_ssize_t offset;
     PyObject *proto;
-    void *deref = locked_deref(self);
+    void *deref = *(void **)self->b_ptr;
 
     if (deref == NULL) {
         PyErr_SetString(PyExc_ValueError,
@@ -5364,8 +5364,23 @@ Pointer_item(PyObject *myself, Py_ssize_t index)
                        index, size, (char *)((char *)deref + offset));
 }
 
+static PyObject *
+Pointer_item(PyObject *myself, Py_ssize_t index)
+{
+    CDataObject *self = _CDataObject_CAST(myself);
+    PyObject *res;
+    // TODO: The plan is to make LOCK_PTR() a mutex instead of a critical
+    // section someday, so when that happens, this needs to get refactored
+    // to be re-entrant safe.
+    // This goes for all the locks here.
+    LOCK_PTR(self);
+    res = Pointer_item_lock_held(myself, index);
+    UNLOCK_PTR(self);
+    return res;
+}
+
 static int
-Pointer_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value)
+Pointer_ass_item_lock_held(PyObject *myself, Py_ssize_t index, PyObject *value)
 {
     CDataObject *self = _CDataObject_CAST(myself);
     Py_ssize_t size;
@@ -5378,7 +5393,7 @@ Pointer_ass_item(PyObject *myself, Py_ssize_t index, 
PyObject *value)
         return -1;
     }
 
-    void *deref = locked_deref(self);
+    void *deref = *(void **)self->b_ptr;
     if (deref == NULL) {
         PyErr_SetString(PyExc_ValueError,
                         "NULL pointer access");
@@ -5409,10 +5424,21 @@ Pointer_ass_item(PyObject *myself, Py_ssize_t index, 
PyObject *value)
                        index, size, ((char *)deref + offset));
 }
 
+static int
+Pointer_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value)
+{
+    CDataObject *self = _CDataObject_CAST(myself);
+    int res;
+    LOCK_PTR(self);
+    res = Pointer_ass_item_lock_held(myself, index, value);
+    UNLOCK_PTR(self);
+    return res;
+}
+
 static PyObject *
-Pointer_get_contents(PyObject *self, void *closure)
+Pointer_get_contents_lock_held(PyObject *self, void *closure)
 {
-    void *deref = locked_deref(_CDataObject_CAST(self));
+    void *deref = *(void **)_CDataObject_CAST(self)->b_ptr;
     if (deref == NULL) {
         PyErr_SetString(PyExc_ValueError,
                         "NULL pointer access");
@@ -5429,6 +5455,17 @@ Pointer_get_contents(PyObject *self, void *closure)
     return PyCData_FromBaseObj(st, stginfo->proto, self, 0, deref);
 }
 
+static PyObject *
+Pointer_get_contents(PyObject *myself, void *closure)
+{
+    CDataObject *self = _CDataObject_CAST(myself);
+    PyObject *res;
+    LOCK_PTR(self);
+    res = Pointer_get_contents_lock_held(myself, closure);
+    UNLOCK_PTR(self);
+    return res;
+}
+
 static int
 Pointer_set_contents(PyObject *op, PyObject *value, void *closure)
 {
@@ -5462,7 +5499,15 @@ Pointer_set_contents(PyObject *op, PyObject *value, void 
*closure)
     }
 
     dst = (CDataObject *)value;
-    locked_deref_assign(self, dst->b_ptr);
+    if (dst != self) {
+        LOCK_PTR(dst);
+        locked_deref_assign(self, dst->b_ptr);
+        UNLOCK_PTR(dst);
+    } else {
+        LOCK_PTR(self);
+        *((void **)self->b_ptr) = dst->b_ptr;
+        UNLOCK_PTR(self);
+    }
 
     /*
        A Pointer instance must keep the value it points to alive.  So, a
@@ -5514,6 +5559,23 @@ Pointer_new(PyTypeObject *type, PyObject *args, PyObject 
*kw)
     return generic_pycdata_new(st, type, args, kw);
 }
 
+static int
+copy_pointer_to_list_lock_held(PyObject *myself, PyObject *np, Py_ssize_t len,
+                               Py_ssize_t start, Py_ssize_t step)
+{
+    Py_ssize_t i;
+    size_t cur;
+    for (cur = start, i = 0; i < len; cur += step, i++) {
+        PyObject *v = Pointer_item_lock_held(myself, cur);
+        if (!v) {
+            return -1;
+        }
+        PyList_SET_ITEM(np, i, v);
+    }
+
+    return 0;
+}
+
 static PyObject *
 Pointer_subscript(PyObject *myself, PyObject *item)
 {
@@ -5595,7 +5657,6 @@ Pointer_subscript(PyObject *myself, PyObject *item)
         }
         assert(iteminfo);
         if (iteminfo->getfunc == _ctypes_get_fielddesc("c")->getfunc) {
-            char *ptr = locked_deref(self);
             char *dest;
 
             if (len <= 0)
@@ -5603,6 +5664,7 @@ Pointer_subscript(PyObject *myself, PyObject *item)
             if (step == 1) {
                 PyObject *res;
                 LOCK_PTR(self);
+                char *ptr = *(void **)self->b_ptr;
                 res = PyBytes_FromStringAndSize(ptr + start,
                                                 len);
                 UNLOCK_PTR(self);
@@ -5612,6 +5674,7 @@ Pointer_subscript(PyObject *myself, PyObject *item)
             if (dest == NULL)
                 return PyErr_NoMemory();
             LOCK_PTR(self);
+            char *ptr = *(void **)self->b_ptr;
             for (cur = start, i = 0; i < len; cur += step, i++) {
                 dest[i] = ptr[cur];
             }
@@ -5621,7 +5684,6 @@ Pointer_subscript(PyObject *myself, PyObject *item)
             return np;
         }
         if (iteminfo->getfunc == _ctypes_get_fielddesc("u")->getfunc) {
-            wchar_t *ptr = locked_deref(self);
             wchar_t *dest;
 
             if (len <= 0)
@@ -5629,6 +5691,7 @@ Pointer_subscript(PyObject *myself, PyObject *item)
             if (step == 1) {
                 PyObject *res;
                 LOCK_PTR(self);
+                wchar_t *ptr = *(wchar_t **)self->b_ptr;
                 res = PyUnicode_FromWideChar(ptr + start,
                                              len);
                 UNLOCK_PTR(self);
@@ -5638,6 +5701,7 @@ Pointer_subscript(PyObject *myself, PyObject *item)
             if (dest == NULL)
                 return PyErr_NoMemory();
             LOCK_PTR(self);
+            wchar_t *ptr = *(wchar_t **)self->b_ptr;
             for (cur = start, i = 0; i < len; cur += step, i++) {
                 dest[i] = ptr[cur];
             }
@@ -5651,14 +5715,15 @@ Pointer_subscript(PyObject *myself, PyObject *item)
         if (np == NULL)
             return NULL;
 
-        for (cur = start, i = 0; i < len; cur += step, i++) {
-            PyObject *v = Pointer_item(myself, cur);
-            if (!v) {
-                Py_DECREF(np);
-                return NULL;
-            }
-            PyList_SET_ITEM(np, i, v);
+        int res;
+        LOCK_PTR(self);
+        res = copy_pointer_to_list_lock_held(myself, np, len, start, step);
+        UNLOCK_PTR(self);
+        if (res < 0) {
+            Py_DECREF(np);
+            return NULL;
         }
+
         return np;
     }
     else {

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to