]> granicus.if.org Git - python/commitdiff
Issue #24097: Fixed crash in object.__reduce__() if slot name is freed inside
authorSerhiy Storchaka <storchaka@gmail.com>
Wed, 25 Nov 2015 16:35:33 +0000 (18:35 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Wed, 25 Nov 2015 16:35:33 +0000 (18:35 +0200)
__getattr__.  Original patch by Antoine Pitrou.

Lib/test/test_descr.py
Misc/NEWS
Objects/typeobject.c

index 25f65c5a2c8587e803f18b2ffb9da37d62b36455..0861bcc37ca782e81f5fb39b9fc4222928c64811 100644 (file)
@@ -4763,6 +4763,26 @@ class PTypesLongInitTest(unittest.TestCase):
         type.mro(tuple)
 
 
+class PicklingTests(unittest.TestCase):
+
+    def test_issue24097(self):
+        # Slot name is freed inside __getattr__ and is later used.
+        class S(str):  # Not interned
+            pass
+        class A(object):
+            __slotnames__ = [S('spam')]
+            def __getattr__(self, attr):
+                if attr == 'spam':
+                    A.__slotnames__[:] = [S('spam')]
+                    return 42
+                else:
+                    raise AttributeError
+
+        import copy_reg
+        expected = (copy_reg.__newobj__, (A,), ({}, {'spam': 42}), None, None)
+        self.assertEqual(A().__reduce__(2), expected)
+
+
 def test_main():
     deprecations = [(r'complex divmod\(\), // and % are deprecated$',
                      DeprecationWarning)]
@@ -4774,7 +4794,8 @@ def test_main():
     with test_support.check_warnings(*deprecations):
         # Run all local test cases, with PTypesLongInitTest first.
         test_support.run_unittest(PTypesLongInitTest, OperatorsTest,
-                                  ClassPropertiesAndMethods, DictProxyTests)
+                                  ClassPropertiesAndMethods, DictProxyTests,
+                                  PicklingTests)
 
 if __name__ == "__main__":
     test_main()
index a95f649f7e67b17a615a384436a847364ee573b7..c765aa32e56d3a5bee79497ac39976330fa3d1b5 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ What's New in Python 2.7.12?
 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
   __str__, __trunc__, and __float__ returning instances of subclasses of
   str, long, and float to subclasses of str, long, and float correspondingly.
index 720a84e97e0d44a6a3ca8c0bad6d8102e755b4f5..38548fdce996b5738748726788ac4a87dd8004b6 100644 (file)
@@ -3269,12 +3269,16 @@ reduce_2(PyObject *obj)
             for (i = 0; i < PyList_GET_SIZE(names); i++) {
                 PyObject *name, *value;
                 name = PyList_GET_ITEM(names, i);
+                Py_INCREF(name);
                 value = PyObject_GetAttr(obj, name);
-                if (value == NULL)
+                if (value == NULL) {
+                    Py_DECREF(name);
                     PyErr_Clear();
+                }
                 else {
                     int err = PyDict_SetItem(slots, name,
                                              value);
+                    Py_DECREF(name);
                     Py_DECREF(value);
                     if (err)
                         goto end;