gh-107940: Only reuse the pointer object when it matches the _type_ of the container#108222
gh-107940: Only reuse the pointer object when it matches the _type_ of the container#108222ambv wants to merge 2 commits into
_type_ of the container#108222Conversation
|
Skipping news as this is a fix for a yet unreleased regression. |
Sorry, something went wrong.
|
Yep, there's a bug for sure, I had an intuition that if one would come up with some interesting way to cast things, we can break things, just couldn't come up with an example back then. |
Sorry, something went wrong.
|
I definitely got something weird, that I can't quickly figure out: def test_pointer_set_contents(self):
class Struct(Structure):
_fields_ = [('a', c_int16)]
p = pointer(Struct(a=23))
self.assertIs(p._type_, Struct)
self.assertEqual(cast(p, POINTER(c_int16)).contents._type_, 'h')
pp = pointer(p)
self.assertIs(pp._type_, POINTER(Struct))
cast(pp, POINTER(POINTER(c_int16))).contents.contents = c_int16(32)
self.assertIs(p.contents, pp.contents.contents)
self.assertEqual(cast(p, POINTER(c_int16)).contents.value, 32)
self.assertEqual(p[0].a, 32) # works
self.assertEqual(pp[0].contents.a, 32) # works
self.assertEqual(pp.contents[0].a, 32) # works
self.assertEqual(pp.contents.contents.a, 32) # fails, wat, holds 23
self.assertEqual(p.contents.a, 32) # fails, wat, holds 23 |
Sorry, something went wrong.
|
I can't repro your result. For me |
Sorry, something went wrong.
|
Very interesting. If you're OK with this, I can spend some time this week investigating too. |
Sorry, something went wrong.
|
Sure. We might need to back out your original fix out of 3.11 until those rough edges are addressed as the next release is going to likely go out either today or tomorrow. |
Sorry, something went wrong.
|
I have a partial solution: ptr2ptr = (CDataObject*) PyDict_GetItemString(keep, "1");
if (ptr2ptr == NULL) {
PyErr_SetString(PyExc_ValueError,
"Unexpected NULL pointer in _objects");
return NULL;
}
// if we need to return a pointer, an array or a structure,
// Pointer_item will do the right thing
if (
PyCStructTypeObject_Check(stgdict->proto) ||
PyCArrayTypeObject_Check(stgdict->proto) ||
PyCPointerTypeObject_Check(stgdict->proto)
) {
return Pointer_item(self, 0);
} else if ( PyUnicode_Check(stgdict->proto)
&& (strchr("sPzUZXO", PyUnicode_AsUTF8(stgdict->proto)[0]))) {
// simple pointer types, c_void_p, c_wchar_p, BSTR, ... */
return Pointer_item(self, 0);
}So, basically, if we are about to return Pointer, Structure or an Array, back off to the same thing as It messes up a bit the garbage collection: replaced values are gonna be saved longer than needed. Still, I think it's a better solution, than what we have now in 3.11, where a memory leak can happen. |
Sorry, something went wrong.
…tainer Closes python#107940. Also, solves a related yet undiscovered issue where an array of pointers reuses the array's memory for the pointer objects.
Closes #107940. Also, solves a related yet undiscovered issue where an array of pointers reuses the array's memory for the pointer objects.