Issue #24097: Fixed crash in object.__reduce__() if slot name is freed inside

__getattr__.  Original patch by Antoine Pitrou.
This commit is contained in:
Serhiy Storchaka 2015-11-25 18:35:15 +02:00
commit 6a50e79130
3 changed files with 23 additions and 0 deletions

View File

@ -5085,6 +5085,23 @@ class PicklingTests(unittest.TestCase):
objcopy2 = deepcopy(objcopy) objcopy2 = deepcopy(objcopy)
self._assert_is_copy(obj, objcopy2) self._assert_is_copy(obj, objcopy2)
def test_issue24097(self):
# Slot name is freed inside __getattr__ and is later used.
class S(str): # Not interned
pass
class A:
__slotnames__ = [S('spam')]
def __getattr__(self, attr):
if attr == 'spam':
A.__slotnames__[:] = [S('spam')]
return 42
else:
raise AttributeError
import copyreg
expected = (copyreg.__newobj__, (A,), (None, {'spam': 42}), None, None)
self.assertEqual(A().__reduce__(2), expected) # Shouldn't crash
class SharedKeyTests(unittest.TestCase): class SharedKeyTests(unittest.TestCase):

View File

@ -10,6 +10,9 @@ Release date: XXXX-XX-XX
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #24097: Fixed crash in object.__reduce__() if slot name is freed inside
__getattr__.
- Issue #24731: Fixed crash on converting objects with special methods - Issue #24731: Fixed crash on converting objects with special methods
__bytes__, __trunc__, and __float__ returning instances of subclasses of __bytes__, __trunc__, and __float__ returning instances of subclasses of
bytes, int, and float to subclasses of bytes, int, and float correspondingly. bytes, int, and float to subclasses of bytes, int, and float correspondingly.

View File

@ -3897,8 +3897,10 @@ _PyObject_GetState(PyObject *obj)
PyObject *name, *value; PyObject *name, *value;
name = PyList_GET_ITEM(slotnames, i); name = PyList_GET_ITEM(slotnames, i);
Py_INCREF(name);
value = PyObject_GetAttr(obj, name); value = PyObject_GetAttr(obj, name);
if (value == NULL) { if (value == NULL) {
Py_DECREF(name);
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
goto error; goto error;
} }
@ -3907,6 +3909,7 @@ _PyObject_GetState(PyObject *obj)
} }
else { else {
int err = PyDict_SetItem(slots, name, value); int err = PyDict_SetItem(slots, name, value);
Py_DECREF(name);
Py_DECREF(value); Py_DECREF(value);
if (err) { if (err) {
goto error; goto error;