[Python-checkins] cpython (2.7): Issue #24097: Fixed crash in object.__reduce__() if slot name is freed inside

serhiy.storchaka python-checkins at python.org
Wed Nov 25 11:36:04 EST 2015


https://hg.python.org/cpython/rev/4a201d0d4d1e
changeset:   99359:4a201d0d4d1e
branch:      2.7
parent:      99355:afaad8dc8edf
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Wed Nov 25 18:35:33 2015 +0200
summary:
  Issue #24097: Fixed crash in object.__reduce__() if slot name is freed inside
__getattr__.  Original patch by Antoine Pitrou.

files:
  Lib/test/test_descr.py |  23 ++++++++++++++++++++++-
  Misc/NEWS              |   3 +++
  Objects/typeobject.c   |   6 +++++-
  3 files changed, 30 insertions(+), 2 deletions(-)


diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -4763,6 +4763,26 @@
         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 @@
     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()
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
 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.
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -3269,12 +3269,16 @@
             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;

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list