Issue #25761: Added more test cases for testing unpickling broken data.
Output raised exception at verbose level 2 (-vv).
This commit is contained in:
parent
c472246d81
commit
7279befccb
|
@ -11,8 +11,9 @@ import unittest
|
|||
import weakref
|
||||
from http.cookies import SimpleCookie
|
||||
|
||||
from test import support
|
||||
from test.support import (
|
||||
TestFailed, TESTFN, run_with_locale, no_tracing, captured_stdout,
|
||||
TestFailed, TESTFN, run_with_locale, no_tracing,
|
||||
_2G, _4G, bigmemtest,
|
||||
)
|
||||
|
||||
|
@ -679,6 +680,17 @@ class AbstractUnpickleTests(unittest.TestCase):
|
|||
self.assertEqual(getattr(obj, slot, None),
|
||||
getattr(objcopy, slot, None), msg=msg)
|
||||
|
||||
def check_unpickling_error(self, errors, data):
|
||||
with self.subTest(data=data), \
|
||||
self.assertRaises(errors):
|
||||
try:
|
||||
self.loads(data)
|
||||
except BaseException as exc:
|
||||
if support.verbose > 1:
|
||||
print('%-32r - %s: %s' %
|
||||
(data, exc.__class__.__name__, exc))
|
||||
raise
|
||||
|
||||
def test_load_from_data0(self):
|
||||
self.assert_is_copy(self._testdata, self.loads(DATA0))
|
||||
|
||||
|
@ -759,12 +771,7 @@ class AbstractUnpickleTests(unittest.TestCase):
|
|||
|
||||
# Try too with a bogus literal.
|
||||
data = b'I' + str(maxint64).encode("ascii") + b'JUNK\n.'
|
||||
self.assertRaises(ValueError, self.loads, data)
|
||||
|
||||
def test_pop_empty_stack(self):
|
||||
# Test issue7455
|
||||
s = b'0'
|
||||
self.assertRaises((pickle.UnpicklingError, IndexError), self.loads, s)
|
||||
self.check_unpickling_error(ValueError, data)
|
||||
|
||||
def test_unpickle_from_2x(self):
|
||||
# Unpickle non-trivial data from Python 2.x.
|
||||
|
@ -849,22 +856,22 @@ class AbstractUnpickleTests(unittest.TestCase):
|
|||
def test_negative_32b_binbytes(self):
|
||||
# On 32-bit builds, a BINBYTES of 2**31 or more is refused
|
||||
dumped = b'\x80\x03B\xff\xff\xff\xffxyzq\x00.'
|
||||
with self.assertRaises((pickle.UnpicklingError, OverflowError)):
|
||||
self.loads(dumped)
|
||||
self.check_unpickling_error((pickle.UnpicklingError, OverflowError),
|
||||
dumped)
|
||||
|
||||
@requires_32b
|
||||
def test_negative_32b_binunicode(self):
|
||||
# On 32-bit builds, a BINUNICODE of 2**31 or more is refused
|
||||
dumped = b'\x80\x03X\xff\xff\xff\xffxyzq\x00.'
|
||||
with self.assertRaises((pickle.UnpicklingError, OverflowError)):
|
||||
self.loads(dumped)
|
||||
self.check_unpickling_error((pickle.UnpicklingError, OverflowError),
|
||||
dumped)
|
||||
|
||||
def test_short_binunicode(self):
|
||||
dumped = b'\x80\x04\x8c\x04\xe2\x82\xac\x00.'
|
||||
self.assertEqual(self.loads(dumped), '\u20ac\x00')
|
||||
|
||||
def test_misc_get(self):
|
||||
self.assertRaises(KeyError, self.loads, b'g0\np0')
|
||||
self.check_unpickling_error(KeyError, b'g0\np0')
|
||||
self.assert_is_copy([(100,), (100,)],
|
||||
self.loads(b'((Kdtp0\nh\x00l.))'))
|
||||
|
||||
|
@ -879,14 +886,14 @@ class AbstractUnpickleTests(unittest.TestCase):
|
|||
@requires_32b
|
||||
def test_large_32b_binbytes8(self):
|
||||
dumped = b'\x80\x04\x8e\4\0\0\0\1\0\0\0\xe2\x82\xac\x00.'
|
||||
with self.assertRaises((pickle.UnpicklingError, OverflowError)):
|
||||
self.loads(dumped)
|
||||
self.check_unpickling_error((pickle.UnpicklingError, OverflowError),
|
||||
dumped)
|
||||
|
||||
@requires_32b
|
||||
def test_large_32b_binunicode8(self):
|
||||
dumped = b'\x80\x04\x8d\4\0\0\0\1\0\0\0\xe2\x82\xac\x00.'
|
||||
with self.assertRaises((pickle.UnpicklingError, OverflowError)):
|
||||
self.loads(dumped)
|
||||
self.check_unpickling_error((pickle.UnpicklingError, OverflowError),
|
||||
dumped)
|
||||
|
||||
def test_get(self):
|
||||
pickled = b'((lp100000\ng100000\nt.'
|
||||
|
@ -915,16 +922,16 @@ class AbstractUnpickleTests(unittest.TestCase):
|
|||
def test_negative_put(self):
|
||||
# Issue #12847
|
||||
dumped = b'Va\np-1\n.'
|
||||
self.assertRaises(ValueError, self.loads, dumped)
|
||||
self.check_unpickling_error(ValueError, dumped)
|
||||
|
||||
@requires_32b
|
||||
def test_negative_32b_binput(self):
|
||||
# Issue #12847
|
||||
dumped = b'\x80\x03X\x01\x00\x00\x00ar\xff\xff\xff\xff.'
|
||||
self.assertRaises(ValueError, self.loads, dumped)
|
||||
self.check_unpickling_error(ValueError, dumped)
|
||||
|
||||
def test_badly_escaped_string(self):
|
||||
self.assertRaises(ValueError, self.loads, b"S'\\'\n.")
|
||||
self.check_unpickling_error(ValueError, b"S'\\'\n.")
|
||||
|
||||
def test_badly_quoted_string(self):
|
||||
# Issue #17710
|
||||
|
@ -942,7 +949,7 @@ class AbstractUnpickleTests(unittest.TestCase):
|
|||
b'S\n.',
|
||||
b'S.']
|
||||
for p in badpickles:
|
||||
self.assertRaises(pickle.UnpicklingError, self.loads, p)
|
||||
self.check_unpickling_error(pickle.UnpicklingError, p)
|
||||
|
||||
def test_correctly_quoted_string(self):
|
||||
goodpickles = [(b"S''\n.", ''),
|
||||
|
@ -989,86 +996,183 @@ class AbstractUnpickleTests(unittest.TestCase):
|
|||
|
||||
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
|
||||
b'.', # STOP
|
||||
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', # PyUnpickler doesn't raise
|
||||
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)
|
||||
self.check_unpickling_error(self.bad_stack_errors, 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.',
|
||||
# b'N(.', # STOP
|
||||
b'N(2', # DUP
|
||||
b'cbuiltins\nlist\n)(R', # REDUCE
|
||||
b'cbuiltins\nlist\n()R',
|
||||
b']N(a', # APPEND
|
||||
# BUILD
|
||||
b'cbuiltins\nValueError\n)R}(b',
|
||||
b'cbuiltins\nValueError\n)R(}b',
|
||||
b'(Nd', # DICT
|
||||
b'N(p1\n', # PUT
|
||||
b'N(q\x00', # BINPUT
|
||||
b'N(r\x00\x00\x00\x00', # LONG_BINPUT
|
||||
b'}NN(s', # SETITEM
|
||||
b'}N(Ns',
|
||||
b'}(NNs',
|
||||
b'}((u', # SETITEMS
|
||||
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']((\x90', # ADDITEMS
|
||||
# NEWOBJ_EX
|
||||
b'cbuiltins\nlist\n)}(\x92',
|
||||
b'cbuiltins\nlist\n)(}\x92',
|
||||
b'cbuiltins\nlist\n()}\x92',
|
||||
# STACK_GLOBAL
|
||||
b'Vbuiltins\n(Vlist\n\x93',
|
||||
b'Vbuiltins\nVlist\n(\x93',
|
||||
b'N(\x94', # MEMOIZE
|
||||
]
|
||||
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
|
||||
self.check_unpickling_error(self.bad_mark_errors, p)
|
||||
|
||||
def test_truncated_data(self):
|
||||
self.check_unpickling_error(EOFError, b'')
|
||||
self.check_unpickling_error(EOFError, b'N')
|
||||
badpickles = [
|
||||
b'B', # BINBYTES
|
||||
b'B\x03\x00\x00',
|
||||
b'B\x03\x00\x00\x00',
|
||||
b'B\x03\x00\x00\x00ab',
|
||||
b'C', # SHORT_BINBYTES
|
||||
b'C\x03',
|
||||
b'C\x03ab',
|
||||
b'F', # FLOAT
|
||||
b'F0.0',
|
||||
b'F0.00',
|
||||
b'G', # BINFLOAT
|
||||
b'G\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'I', # INT
|
||||
b'I0',
|
||||
b'J', # BININT
|
||||
b'J\x00\x00\x00',
|
||||
b'K', # BININT1
|
||||
b'L', # LONG
|
||||
b'L0',
|
||||
b'L10',
|
||||
b'L0L',
|
||||
b'L10L',
|
||||
b'M', # BININT2
|
||||
b'M\x00',
|
||||
# b'P', # PERSID
|
||||
# b'Pabc',
|
||||
b'S', # STRING
|
||||
b"S'abc'",
|
||||
b'T', # BINSTRING
|
||||
b'T\x03\x00\x00',
|
||||
b'T\x03\x00\x00\x00',
|
||||
b'T\x03\x00\x00\x00ab',
|
||||
b'U', # SHORT_BINSTRING
|
||||
b'U\x03',
|
||||
b'U\x03ab',
|
||||
b'V', # UNICODE
|
||||
b'Vabc',
|
||||
b'X', # BINUNICODE
|
||||
b'X\x03\x00\x00',
|
||||
b'X\x03\x00\x00\x00',
|
||||
b'X\x03\x00\x00\x00ab',
|
||||
b'(c', # GLOBAL
|
||||
b'(cbuiltins',
|
||||
b'(cbuiltins\n',
|
||||
b'(cbuiltins\nlist',
|
||||
b'Ng', # GET
|
||||
b'Ng0',
|
||||
b'(i', # INST
|
||||
b'(ibuiltins',
|
||||
b'(ibuiltins\n',
|
||||
b'(ibuiltins\nlist',
|
||||
b'Nh', # BINGET
|
||||
b'Nj', # LONG_BINGET
|
||||
b'Nj\x00\x00\x00',
|
||||
b'Np', # PUT
|
||||
b'Np0',
|
||||
b'Nq', # BINPUT
|
||||
b'Nr', # LONG_BINPUT
|
||||
b'Nr\x00\x00\x00',
|
||||
b'\x80', # PROTO
|
||||
b'\x82', # EXT1
|
||||
b'\x83', # EXT2
|
||||
b'\x84\x01',
|
||||
b'\x84', # EXT4
|
||||
b'\x84\x01\x00\x00',
|
||||
b'\x8a', # LONG1
|
||||
b'\x8b', # LONG4
|
||||
b'\x8b\x00\x00\x00',
|
||||
b'\x8c', # SHORT_BINUNICODE
|
||||
b'\x8c\x03',
|
||||
b'\x8c\x03ab',
|
||||
b'\x8d', # BINUNICODE8
|
||||
b'\x8d\x03\x00\x00\x00\x00\x00\x00',
|
||||
b'\x8d\x03\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'\x8d\x03\x00\x00\x00\x00\x00\x00\x00ab',
|
||||
b'\x8e', # BINBYTES8
|
||||
b'\x8e\x03\x00\x00\x00\x00\x00\x00',
|
||||
b'\x8e\x03\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'\x8e\x03\x00\x00\x00\x00\x00\x00\x00ab',
|
||||
b'\x95', # FRAME
|
||||
b'\x95\x02\x00\x00\x00\x00\x00\x00',
|
||||
b'\x95\x02\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'\x95\x02\x00\x00\x00\x00\x00\x00\x00N',
|
||||
]
|
||||
for p in badpickles:
|
||||
self.check_unpickling_error(self.truncated_errors, p)
|
||||
|
||||
|
||||
class AbstractPickleTests(unittest.TestCase):
|
||||
|
|
|
@ -33,6 +33,11 @@ class PyUnpicklerTests(AbstractUnpickleTests):
|
|||
|
||||
unpickler = pickle._Unpickler
|
||||
bad_stack_errors = (IndexError,)
|
||||
bad_mark_errors = (IndexError, pickle.UnpicklingError,
|
||||
TypeError, AttributeError, EOFError)
|
||||
truncated_errors = (pickle.UnpicklingError, EOFError,
|
||||
AttributeError, ValueError,
|
||||
struct.error, IndexError, ImportError)
|
||||
|
||||
def loads(self, buf, **kwds):
|
||||
f = io.BytesIO(buf)
|
||||
|
@ -64,6 +69,11 @@ class InMemoryPickleTests(AbstractPickleTests, AbstractUnpickleTests,
|
|||
pickler = pickle._Pickler
|
||||
unpickler = pickle._Unpickler
|
||||
bad_stack_errors = (pickle.UnpicklingError, IndexError)
|
||||
bad_mark_errors = (pickle.UnpicklingError, IndexError,
|
||||
TypeError, AttributeError, EOFError)
|
||||
truncated_errors = (pickle.UnpicklingError, EOFError,
|
||||
AttributeError, ValueError,
|
||||
struct.error, IndexError, ImportError)
|
||||
|
||||
def dumps(self, arg, protocol=None):
|
||||
return pickle.dumps(arg, protocol)
|
||||
|
@ -122,6 +132,9 @@ if has_c_implementation:
|
|||
class CUnpicklerTests(PyUnpicklerTests):
|
||||
unpickler = _pickle.Unpickler
|
||||
bad_stack_errors = (pickle.UnpicklingError,)
|
||||
bad_mark_errors = (EOFError,)
|
||||
truncated_errors = (pickle.UnpicklingError, EOFError,
|
||||
AttributeError, ValueError)
|
||||
|
||||
class CPicklerTests(PyPicklerTests):
|
||||
pickler = _pickle.Pickler
|
||||
|
|
Loading…
Reference in New Issue