mirror of
https://github.com/python/cpython.git
synced 2025-10-12 01:43:12 +00:00
Issue #23914: Fixed SystemError raised by unpickler on broken pickle data.
This commit is contained in:
parent
b6aa5375d5
commit
e9b3074cf9
4 changed files with 105 additions and 4 deletions
|
@ -12,7 +12,7 @@ import weakref
|
||||||
from http.cookies import SimpleCookie
|
from http.cookies import SimpleCookie
|
||||||
|
|
||||||
from test.support import (
|
from test.support import (
|
||||||
TestFailed, TESTFN, run_with_locale, no_tracing,
|
TestFailed, TESTFN, run_with_locale, no_tracing, captured_stdout,
|
||||||
_2G, _4G, bigmemtest,
|
_2G, _4G, bigmemtest,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -987,6 +987,89 @@ class AbstractUnpickleTests(unittest.TestCase):
|
||||||
self.assertIs(type(unpickled), collections.UserDict)
|
self.assertIs(type(unpickled), collections.UserDict)
|
||||||
self.assertEqual(unpickled, collections.UserDict({1: 2}))
|
self.assertEqual(unpickled, collections.UserDict({1: 2}))
|
||||||
|
|
||||||
|
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'ibuiltins\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.',
|
||||||
|
b'\x90.', # ADDITEMS
|
||||||
|
# b'(\x90.', # PyUnpickler raises AttributeError
|
||||||
|
b'\x91.', # FROZENSET
|
||||||
|
b'\x92.', # NEWOBJ_EX
|
||||||
|
b')}\x92.',
|
||||||
|
b'\x93.', # STACK_GLOBAL
|
||||||
|
b'Vlist\n\x93.',
|
||||||
|
b'\x94.', # MEMOIZE
|
||||||
|
]
|
||||||
|
for p in badpickles:
|
||||||
|
with self.subTest(p):
|
||||||
|
self.assertRaises(self.bad_stack_errors, self.loads, p)
|
||||||
|
|
||||||
|
def test_bad_mark(self):
|
||||||
|
badpickles = [
|
||||||
|
b'cbuiltins\nlist\n)(R.', # REDUCE
|
||||||
|
b'cbuiltins\nlist\n()R.',
|
||||||
|
b']N(a.', # APPEND
|
||||||
|
b'cbuiltins\nValueError\n)R}(b.', # BUILD
|
||||||
|
b'cbuiltins\nValueError\n)R(}b.',
|
||||||
|
b'(Nd.', # DICT
|
||||||
|
b'}NN(s.', # SETITEM
|
||||||
|
b'}N(Ns.',
|
||||||
|
b'cbuiltins\nlist\n)(\x81.', # NEWOBJ
|
||||||
|
b'cbuiltins\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.',
|
||||||
|
b'cbuiltins\nlist\n)}(\x92.', # NEWOBJ_EX
|
||||||
|
b'cbuiltins\nlist\n)(}\x92.',
|
||||||
|
b'cbuiltins\nlist\n()}\x92.',
|
||||||
|
b'Vbuiltins\n(Vlist\n\x93.', # STACK_GLOBAL
|
||||||
|
b'Vbuiltins\nVlist\n(\x93.',
|
||||||
|
]
|
||||||
|
for p in badpickles:
|
||||||
|
# PyUnpickler prints reduce errors to stdout
|
||||||
|
with self.subTest(p), captured_stdout():
|
||||||
|
try:
|
||||||
|
self.loads(p)
|
||||||
|
except (IndexError, AttributeError, TypeError,
|
||||||
|
pickle.UnpicklingError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AbstractPickleTests(unittest.TestCase):
|
class AbstractPickleTests(unittest.TestCase):
|
||||||
# Subclass must define self.dumps, self.loads.
|
# Subclass must define self.dumps, self.loads.
|
||||||
|
|
|
@ -32,6 +32,7 @@ class PickleTests(AbstractPickleModuleTests):
|
||||||
class PyUnpicklerTests(AbstractUnpickleTests):
|
class PyUnpicklerTests(AbstractUnpickleTests):
|
||||||
|
|
||||||
unpickler = pickle._Unpickler
|
unpickler = pickle._Unpickler
|
||||||
|
bad_stack_errors = (IndexError,)
|
||||||
|
|
||||||
def loads(self, buf, **kwds):
|
def loads(self, buf, **kwds):
|
||||||
f = io.BytesIO(buf)
|
f = io.BytesIO(buf)
|
||||||
|
@ -62,6 +63,7 @@ class InMemoryPickleTests(AbstractPickleTests, AbstractUnpickleTests,
|
||||||
|
|
||||||
pickler = pickle._Pickler
|
pickler = pickle._Pickler
|
||||||
unpickler = pickle._Unpickler
|
unpickler = pickle._Unpickler
|
||||||
|
bad_stack_errors = (pickle.UnpicklingError, IndexError)
|
||||||
|
|
||||||
def dumps(self, arg, protocol=None):
|
def dumps(self, arg, protocol=None):
|
||||||
return pickle.dumps(arg, protocol)
|
return pickle.dumps(arg, protocol)
|
||||||
|
@ -119,6 +121,7 @@ class PyChainDispatchTableTests(AbstractDispatchTableTests):
|
||||||
if has_c_implementation:
|
if has_c_implementation:
|
||||||
class CUnpicklerTests(PyUnpicklerTests):
|
class CUnpicklerTests(PyUnpicklerTests):
|
||||||
unpickler = _pickle.Unpickler
|
unpickler = _pickle.Unpickler
|
||||||
|
bad_stack_errors = (pickle.UnpicklingError,)
|
||||||
|
|
||||||
class CPicklerTests(PyPicklerTests):
|
class CPicklerTests(PyPicklerTests):
|
||||||
pickler = _pickle.Pickler
|
pickler = _pickle.Pickler
|
||||||
|
|
|
@ -106,6 +106,8 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #23914: Fixed SystemError raised by unpickler on broken pickle data.
|
||||||
|
|
||||||
- Issue #25691: Fixed crash on deleting ElementTree.Element attributes.
|
- Issue #25691: Fixed crash on deleting ElementTree.Element attributes.
|
||||||
|
|
||||||
- Issue #25624: ZipFile now always writes a ZIP_STORED header for directory
|
- Issue #25624: ZipFile now always writes a ZIP_STORED header for directory
|
||||||
|
|
|
@ -448,8 +448,8 @@ Pdata_grow(Pdata *self)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
Pdata_pop(Pdata *self)
|
Pdata_pop(Pdata *self)
|
||||||
{
|
{
|
||||||
PickleState *st = _Pickle_GetGlobalState();
|
|
||||||
if (Py_SIZE(self) == 0) {
|
if (Py_SIZE(self) == 0) {
|
||||||
|
PickleState *st = _Pickle_GetGlobalState();
|
||||||
PyErr_SetString(st->UnpicklingError, "bad pickle data");
|
PyErr_SetString(st->UnpicklingError, "bad pickle data");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -5079,6 +5079,9 @@ load_obj(UnpicklerObject *self)
|
||||||
if ((i = marker(self)) < 0)
|
if ((i = marker(self)) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (Py_SIZE(self->stack) - i < 1)
|
||||||
|
return stack_underflow();
|
||||||
|
|
||||||
args = Pdata_poptuple(self->stack, i + 1);
|
args = Pdata_poptuple(self->stack, i + 1);
|
||||||
if (args == NULL)
|
if (args == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -5737,13 +5740,18 @@ do_append(UnpicklerObject *self, Py_ssize_t x)
|
||||||
static int
|
static int
|
||||||
load_append(UnpicklerObject *self)
|
load_append(UnpicklerObject *self)
|
||||||
{
|
{
|
||||||
|
if (Py_SIZE(self->stack) - 1 <= 0)
|
||||||
|
return stack_underflow();
|
||||||
return do_append(self, Py_SIZE(self->stack) - 1);
|
return do_append(self, Py_SIZE(self->stack) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
load_appends(UnpicklerObject *self)
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -5793,7 +5801,10 @@ load_setitem(UnpicklerObject *self)
|
||||||
static int
|
static int
|
||||||
load_setitems(UnpicklerObject *self)
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -5803,6 +5814,8 @@ load_additems(UnpicklerObject *self)
|
||||||
Py_ssize_t mark, len, i;
|
Py_ssize_t mark, len, i;
|
||||||
|
|
||||||
mark = marker(self);
|
mark = marker(self);
|
||||||
|
if (mark < 0)
|
||||||
|
return -1;
|
||||||
len = Py_SIZE(self->stack);
|
len = Py_SIZE(self->stack);
|
||||||
if (mark > len || mark <= 0)
|
if (mark > len || mark <= 0)
|
||||||
return stack_underflow();
|
return stack_underflow();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue