summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorƁukasz Langa <lukasz@langa.pl>2023-07-31 09:16:59 (GMT)
committerGitHub <noreply@github.com>2023-07-31 09:16:59 (GMT)
commit57f27e444175a8a5ffcd86971e06de61c1c38628 (patch)
treed054c2fcabc91abbdea78d65e83dbab616be4134 /Modules
parentaa5f2b1f3cdb5f71f5210d4578d5c68b6dd5e255 (diff)
downloadcpython-57f27e444175a8a5ffcd86971e06de61c1c38628.zip
cpython-57f27e444175a8a5ffcd86971e06de61c1c38628.tar.gz
cpython-57f27e444175a8a5ffcd86971e06de61c1c38628.tar.bz2
[3.11] gh-46376: Return existing pointer when possible in ctypes (GH-107131) (#107488)
(cherry picked from commit 08447b5deb47e2a0df87fa0a0576d300e5c909b4) Co-authored-by: Konstantin <kpp.live+github@gmail.com>
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_ctypes/_ctypes.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index fc73264..9cc5181 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -5158,6 +5158,8 @@ static PyObject *
Pointer_get_contents(CDataObject *self, void *closure)
{
StgDictObject *stgdict;
+ PyObject *keep, *ptr_probe;
+ CDataObject *ptr2ptr;
if (*(void **)self->b_ptr == NULL) {
PyErr_SetString(PyExc_ValueError,
@@ -5167,6 +5169,33 @@ Pointer_get_contents(CDataObject *self, void *closure)
stgdict = PyObject_stgdict((PyObject *)self);
assert(stgdict); /* Cannot be NULL for pointer instances */
+
+ keep = GetKeepedObjects(self);
+ if (keep != NULL) {
+ // check if it's a pointer to a pointer:
+ // pointers will have '0' key in the _objects
+ ptr_probe = PyDict_GetItemString(keep, "0");
+
+ if (ptr_probe != NULL) {
+ ptr2ptr = (CDataObject*) PyDict_GetItemString(keep, "1");
+ if (ptr2ptr == NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "Unexpected NULL pointer in _objects");
+ return NULL;
+ }
+ // don't construct a new object,
+ // return existing one instead to preserve refcount
+ assert(
+ *(void**) self->b_ptr == ptr2ptr->b_ptr ||
+ *(void**) self->b_value.c == ptr2ptr->b_ptr ||
+ *(void**) self->b_ptr == ptr2ptr->b_value.c ||
+ *(void**) self->b_value.c == ptr2ptr->b_value.c
+ ); // double-check that we are returning the same thing
+ Py_INCREF(ptr2ptr);
+ return (PyObject *) ptr2ptr;
+ }
+ }
+
return PyCData_FromBaseObj(stgdict->proto,
(PyObject *)self, 0,
*(void **)self->b_ptr);