[Python-checkins] cpython (2.7): Issue #23914: Fixed SystemError raised by unpickler on broken pickle data.
serhiy.storchaka
python-checkins at python.org
Mon Nov 23 08:21:10 EST 2015
https://hg.python.org/cpython/rev/686fa9439d38
changeset: 99308:686fa9439d38
branch: 2.7
parent: 99298:e3dea2e4f93d
user: Serhiy Storchaka <storchaka at gmail.com>
date: Mon Nov 23 15:20:43 2015 +0200
summary:
Issue #23914: Fixed SystemError raised by unpickler on broken pickle data.
files:
Lib/test/pickletester.py | 74 +++++++++++++++++++++++++++-
Lib/test/test_cpickle.py | 2 +
Lib/test/test_pickle.py | 3 +-
Misc/NEWS | 1 +
Modules/cPickle.c | 24 ++++++++-
5 files changed, 100 insertions(+), 4 deletions(-)
diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
--- a/Lib/test/pickletester.py
+++ b/Lib/test/pickletester.py
@@ -7,7 +7,7 @@
import pickletools
import copy_reg
-from test.test_support import TestFailed, verbose, have_unicode, TESTFN
+from test.test_support import TestFailed, verbose, have_unicode, TESTFN, captured_stdout
try:
from test.test_support import _2G, _1M, precisionbigmemtest
except ImportError:
@@ -634,6 +634,78 @@
self.assertEqual(unpickled, ([],)*2)
self.assertIs(unpickled[0], unpickled[1])
+ def test_bad_stack(self):
+ badpickles = [
+ b'0.', # POP
+ b'1.', # POP_MARK
+ b'2.', # DUP
+ # b'(2.', # PyUnpickler doesn't raise
+ b'R.', # REDUCE
+ b')R.',
+ b'a.', # APPEND
+ b'Na.',
+ b'b.', # BUILD
+ b'Nb.',
+ b'd.', # DICT
+ b'e.', # APPENDS
+ # b'(e.', # PyUnpickler raises AttributeError
+ b'i__builtin__\nlist\n.', # INST
+ b'l.', # LIST
+ b'o.', # OBJ
+ b'(o.',
+ b'p1\n.', # PUT
+ b'q\x00.', # BINPUT
+ b'r\x00\x00\x00\x00.', # LONG_BINPUT
+ b's.', # SETITEM
+ b'Ns.',
+ b'NNs.',
+ b't.', # TUPLE
+ b'u.', # SETITEMS
+ b'(u.',
+ b'}(Nu.',
+ b'\x81.', # NEWOBJ
+ b')\x81.',
+ b'\x85.', # TUPLE1
+ b'\x86.', # TUPLE2
+ b'N\x86.',
+ b'\x87.', # TUPLE3
+ b'N\x87.',
+ b'NN\x87.',
+ ]
+ for p in badpickles:
+ try:
+ self.assertRaises(self.bad_stack_errors, self.loads, p)
+ except:
+ print '***', repr(p)
+ raise
+
+ def test_bad_mark(self):
+ badpickles = [
+ b'c__builtin__\nlist\n)(R.', # REDUCE
+ b'c__builtin__\nlist\n()R.',
+ b']N(a.', # APPEND
+ b'cexceptions\nValueError\n)R}(b.', # BUILD
+ b'cexceptions\nValueError\n)R(}b.',
+ b'(Nd.', # DICT
+ b'}NN(s.', # SETITEM
+ b'}N(Ns.',
+ b'c__builtin__\nlist\n)(\x81.', # NEWOBJ
+ b'c__builtin__\nlist\n()\x81.',
+ b'N(\x85.', # TUPLE1
+ b'NN(\x86.', # TUPLE2
+ b'N(N\x86.',
+ b'NNN(\x87.', # TUPLE3
+ b'NN(N\x87.',
+ b'N(NN\x87.',
+ ]
+ for p in badpickles:
+ # PyUnpickler prints reduce errors to stdout
+ try:
+ self.loads(p)
+ except (IndexError, AttributeError, TypeError,
+ pickle.UnpicklingError):
+ pass
+
class AbstractPickleTests(unittest.TestCase):
# Subclass must define self.dumps, self.loads.
diff --git a/Lib/test/test_cpickle.py b/Lib/test/test_cpickle.py
--- a/Lib/test/test_cpickle.py
+++ b/Lib/test/test_cpickle.py
@@ -51,6 +51,7 @@
error = cPickle.BadPickleGet
module = cPickle
+ bad_stack_errors = (cPickle.UnpicklingError,)
class cPickleUnpicklerTests(AbstractUnpickleTests):
@@ -63,6 +64,7 @@
self.close(f)
error = cPickle.BadPickleGet
+ bad_stack_errors = (cPickle.UnpicklingError,)
class cStringIOCUnpicklerTests(cStringIOMixin, cPickleUnpicklerTests):
pass
diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py
--- a/Lib/test/test_pickle.py
+++ b/Lib/test/test_pickle.py
@@ -23,17 +23,18 @@
module = pickle
error = KeyError
+ bad_stack_errors = (IndexError,)
class UnpicklerTests(AbstractUnpickleTests):
error = KeyError
+ bad_stack_errors = (IndexError,)
def loads(self, buf):
f = StringIO(buf)
u = pickle.Unpickler(f)
return u.load()
-
class PicklerTests(AbstractPickleTests):
def dumps(self, arg, proto=0, fast=0):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -13,6 +13,7 @@
Library
-------
+- Issue #23914: Fixed SystemError raised by CPickle unpickler on broken data.
What's New in Python 2.7.11?
============================
diff --git a/Modules/cPickle.c b/Modules/cPickle.c
--- a/Modules/cPickle.c
+++ b/Modules/cPickle.c
@@ -3945,6 +3945,10 @@
Py_ssize_t i;
if ((i = marker(self)) < 0) return -1;
+
+ if (self->stack->length - i < 1)
+ return stackUnderflow();
+
if (!( tup=Pdata_popTuple(self->stack, i+1))) return -1;
PDATA_POP(self->stack, class);
if (class) {
@@ -4496,6 +4500,8 @@
static int
load_append(Unpicklerobject *self)
{
+ if (self->stack->length - 1 <= 0)
+ return stackUnderflow();
return do_append(self, self->stack->length - 1);
}
@@ -4503,7 +4509,10 @@
static int
load_appends(Unpicklerobject *self)
{
- return do_append(self, marker(self));
+ Py_ssize_t i = marker(self);
+ if (i < 0)
+ return -1;
+ return do_append(self, i);
}
@@ -4515,6 +4524,14 @@
if (!( (len=self->stack->length) >= x
&& x > 0 )) return stackUnderflow();
+ if (len == x) /* nothing to do */
+ return 0;
+ if ((len - x) % 2 != 0) {
+ /* Currupt or hostile pickle -- we never write one like this. */
+ PyErr_SetString(UnpicklingError,
+ "odd number of items for SETITEMS");
+ return -1;
+ }
dict=self->stack->data[x-1];
@@ -4542,7 +4559,10 @@
static int
load_setitems(Unpicklerobject *self)
{
- return do_setitems(self, marker(self));
+ Py_ssize_t i = marker(self);
+ if (i < 0)
+ return -1;
+ return do_setitems(self, i);
}
--
Repository URL: https://hg.python.org/cpython
More information about the Python-checkins
mailing list