[Python-checkins] cpython (2.7): Issue #28925: cPickle now correctly propagates errors when unpickle instances

serhiy.storchaka python-checkins at python.org
Thu Dec 15 05:55:58 EST 2016


https://hg.python.org/cpython/rev/eb830f1511ef
changeset: 105637:eb830f1511ef
branch: 2.7
parent: 105620:f89ef18f9824
user: Serhiy Storchaka <storchaka at gmail.com>
date: Thu Dec 15 12:51:34 2016 +0200
summary:
 Issue #28925: cPickle now correctly propagates errors when unpickle instances
of old-style classes.
files:
 Lib/test/pickletester.py | 43 +++++++++++++++++++++++++++
 Misc/NEWS | 4 ++
 Modules/cPickle.c | 44 ++++-----------------------
 3 files changed, 54 insertions(+), 37 deletions(-)
diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
--- a/Lib/test/pickletester.py
+++ b/Lib/test/pickletester.py
@@ -147,6 +147,17 @@
 class H(object):
 pass
 
+class MyErr(Exception):
+ def __init__(self):
+ pass
+
+class I:
+ def __init__(self, *args, **kwargs):
+ raise MyErr()
+
+ def __getinitargs__(self):
+ return ()
+
 # Hashable mutable key
 class K(object):
 def __init__(self, value):
@@ -165,6 +176,8 @@
 E.__module__ = "__main__"
 __main__.H = H
 H.__module__ = "__main__"
+__main__.I = I
+I.__module__ = "__main__"
 __main__.K = K
 K.__module__ = "__main__"
 
@@ -623,6 +636,36 @@
 'q\x00oq\x01}q\x02b.').replace('X', xname)
 self.assert_is_copy(X(*args), self.loads(pickle2))
 
+ def test_load_classic_instance_error(self):
+ # Issue #28925.
+ # Protocol 0 (text mode pickle):
+ """
+ 0: ( MARK
+ 1: i INST '__main__ I' (MARK at 0)
+ 13: ( MARK
+ 14: d DICT (MARK at 13)
+ 15: b BUILD
+ 16: . STOP
+ """
+ pickle0 = ('(i__main__\n'
+ 'I\n'
+ '(db.')
+ self.assertRaises(MyErr, self.loads, pickle0)
+
+ # Protocol 1 (binary mode pickle)
+ """
+ 0: ( MARK
+ 1: c GLOBAL '__main__ I'
+ 13: o OBJ (MARK at 0)
+ 14: } EMPTY_DICT
+ 15: b BUILD
+ 16: . STOP
+ """
+ pickle1 = ('(c__main__\n'
+ 'I\n'
+ 'o}b.')
+ self.assertRaises(MyErr, self.loads, pickle1)
+
 def test_load_str(self):
 # From Python 2: pickle.dumps('a\x00\xa0', protocol=0)
 self.assertEqual(self.loads("S'a\\x00\\xa0'\n."), 'a\x00\xa0')
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -13,6 +13,10 @@
 Library
 -------
 
+- Issue #28925: cPickle now correctly propagates errors when unpickle instances
+ of old-style classes.
+
+
 What's New in Python 2.7.13
 ===========================
 
diff --git a/Modules/cPickle.c b/Modules/cPickle.c
--- a/Modules/cPickle.c
+++ b/Modules/cPickle.c
@@ -3875,52 +3875,22 @@
 static PyObject *
 Instance_New(PyObject *cls, PyObject *args)
 {
- PyObject *r = 0;
-
 if (PyClass_Check(cls)) {
 int l;
 
- if ((l=PyObject_Size(args)) < 0) goto err;
+ if ((l=PyObject_Size(args)) < 0) return NULL;
 if (!( l )) {
- PyObject *__getinitargs__;
-
- __getinitargs__ = PyObject_GetAttr(cls,
- __getinitargs___str);
- if (!__getinitargs__) {
+ if (!PyObject_HasAttr(cls, __getinitargs___str)) {
 /* We have a class with no __getinitargs__,
 so bypass usual construction */
- PyObject *inst;
-
- PyErr_Clear();
- if (!( inst=PyInstance_NewRaw(cls, NULL)))
- goto err;
- return inst;
+ return PyInstance_NewRaw(cls, NULL);
 }
- Py_DECREF(__getinitargs__);
 }
 
- if ((r=PyInstance_New(cls, args, NULL))) return r;
- else goto err;
- }
-
- if ((r=PyObject_CallObject(cls, args))) return r;
-
- err:
- {
- PyObject *tp, *v, *tb, *tmp_value;
-
- PyErr_Fetch(&tp, &v, &tb);
- tmp_value = v;
- /* NULL occurs when there was a KeyboardInterrupt */
- if (tmp_value == NULL)
- tmp_value = Py_None;
- if ((r = PyTuple_Pack(3, tmp_value, cls, args))) {
- Py_XDECREF(v);
- v=r;
- }
- PyErr_Restore(tp,v,tb);
- }
- return NULL;
+ return PyInstance_New(cls, args, NULL);
+ }
+
+ return PyObject_CallObject(cls, args);
 }
 
 
-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /