Skip to content

Commit 7279bef

Browse files
Issue #25761: Added more test cases for testing unpickling broken data.
Output raised exception at verbose level 2 (-vv).
1 parent c472246 commit 7279bef

File tree

2 files changed

+210
-93
lines changed

2 files changed

+210
-93
lines changed

Lib/test/pickletester.py

Lines changed: 197 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
import weakref
1212
from http.cookies import SimpleCookie
1313

14+
from test import support
1415
from test.support import (
15-
TestFailed, TESTFN, run_with_locale, no_tracing, captured_stdout,
16+
TestFailed, TESTFN, run_with_locale, no_tracing,
1617
_2G, _4G, bigmemtest,
1718
)
1819

@@ -679,6 +680,17 @@ def assert_is_copy(self, obj, objcopy, msg=None):
679680
self.assertEqual(getattr(obj, slot, None),
680681
getattr(objcopy, slot, None), msg=msg)
681682

683+
def check_unpickling_error(self, errors, data):
684+
with self.subTest(data=data), \
685+
self.assertRaises(errors):
686+
try:
687+
self.loads(data)
688+
except BaseException as exc:
689+
if support.verbose > 1:
690+
print('%-32r - %s: %s' %
691+
(data, exc.__class__.__name__, exc))
692+
raise
693+
682694
def test_load_from_data0(self):
683695
self.assert_is_copy(self._testdata, self.loads(DATA0))
684696

@@ -759,12 +771,7 @@ def test_maxint64(self):
759771

760772
# Try too with a bogus literal.
761773
data = b'I' + str(maxint64).encode("ascii") + b'JUNK\n.'
762-
self.assertRaises(ValueError, self.loads, data)
763-
764-
def test_pop_empty_stack(self):
765-
# Test issue7455
766-
s = b'0'
767-
self.assertRaises((pickle.UnpicklingError, IndexError), self.loads, s)
774+
self.check_unpickling_error(ValueError, data)
768775

769776
def test_unpickle_from_2x(self):
770777
# Unpickle non-trivial data from Python 2.x.
@@ -849,22 +856,22 @@ def test_binbytes(self):
849856
def test_negative_32b_binbytes(self):
850857
# On 32-bit builds, a BINBYTES of 2**31 or more is refused
851858
dumped = b'\x80\x03B\xff\xff\xff\xffxyzq\x00.'
852-
with self.assertRaises((pickle.UnpicklingError, OverflowError)):
853-
self.loads(dumped)
859+
self.check_unpickling_error((pickle.UnpicklingError, OverflowError),
860+
dumped)
854861

855862
@requires_32b
856863
def test_negative_32b_binunicode(self):
857864
# On 32-bit builds, a BINUNICODE of 2**31 or more is refused
858865
dumped = b'\x80\x03X\xff\xff\xff\xffxyzq\x00.'
859-
with self.assertRaises((pickle.UnpicklingError, OverflowError)):
860-
self.loads(dumped)
866+
self.check_unpickling_error((pickle.UnpicklingError, OverflowError),
867+
dumped)
861868

862869
def test_short_binunicode(self):
863870
dumped = b'\x80\x04\x8c\x04\xe2\x82\xac\x00.'
864871
self.assertEqual(self.loads(dumped), '\u20ac\x00')
865872

866873
def test_misc_get(self):
867-
self.assertRaises(KeyError, self.loads, b'g0\np0')
874+
self.check_unpickling_error(KeyError, b'g0\np0')
868875
self.assert_is_copy([(100,), (100,)],
869876
self.loads(b'((Kdtp0\nh\x00l.))'))
870877

@@ -879,14 +886,14 @@ def test_binunicode8(self):
879886
@requires_32b
880887
def test_large_32b_binbytes8(self):
881888
dumped = b'\x80\x04\x8e\4\0\0\0\1\0\0\0\xe2\x82\xac\x00.'
882-
with self.assertRaises((pickle.UnpicklingError, OverflowError)):
883-
self.loads(dumped)
889+
self.check_unpickling_error((pickle.UnpicklingError, OverflowError),
890+
dumped)
884891

885892
@requires_32b
886893
def test_large_32b_binunicode8(self):
887894
dumped = b'\x80\x04\x8d\4\0\0\0\1\0\0\0\xe2\x82\xac\x00.'
888-
with self.assertRaises((pickle.UnpicklingError, OverflowError)):
889-
self.loads(dumped)
895+
self.check_unpickling_error((pickle.UnpicklingError, OverflowError),
896+
dumped)
890897

891898
def test_get(self):
892899
pickled = b'((lp100000\ng100000\nt.'
@@ -915,16 +922,16 @@ def test_dup(self):
915922
def test_negative_put(self):
916923
# Issue #12847
917924
dumped = b'Va\np-1\n.'
918-
self.assertRaises(ValueError, self.loads, dumped)
925+
self.check_unpickling_error(ValueError, dumped)
919926

920927
@requires_32b
921928
def test_negative_32b_binput(self):
922929
# Issue #12847
923930
dumped = b'\x80\x03X\x01\x00\x00\x00ar\xff\xff\xff\xff.'
924-
self.assertRaises(ValueError, self.loads, dumped)
931+
self.check_unpickling_error(ValueError, dumped)
925932

926933
def test_badly_escaped_string(self):
927-
self.assertRaises(ValueError, self.loads, b"S'\\'\n.")
934+
self.check_unpickling_error(ValueError, b"S'\\'\n.")
928935

929936
def test_badly_quoted_string(self):
930937
# Issue #17710
@@ -942,7 +949,7 @@ def test_badly_quoted_string(self):
942949
b'S\n.',
943950
b'S.']
944951
for p in badpickles:
945-
self.assertRaises(pickle.UnpicklingError, self.loads, p)
952+
self.check_unpickling_error(pickle.UnpicklingError, p)
946953

947954
def test_correctly_quoted_string(self):
948955
goodpickles = [(b"S''\n.", ''),
@@ -989,86 +996,183 @@ def test_compat_unpickle(self):
989996

990997
def test_bad_stack(self):
991998
badpickles = [
992-
b'0.', # POP
993-
b'1.', # POP_MARK
994-
b'2.', # DUP
995-
# b'(2.', # PyUnpickler doesn't raise
996-
b'R.', # REDUCE
997-
b')R.',
998-
b'a.', # APPEND
999-
b'Na.',
1000-
b'b.', # BUILD
1001-
b'Nb.',
1002-
b'd.', # DICT
1003-
b'e.', # APPENDS
1004-
# b'(e.', # PyUnpickler raises AttributeError
1005-
b'ibuiltins\nlist\n.', # INST
1006-
b'l.', # LIST
1007-
b'o.', # OBJ
1008-
b'(o.',
1009-
b'p1\n.', # PUT
1010-
b'q\x00.', # BINPUT
1011-
b'r\x00\x00\x00\x00.', # LONG_BINPUT
1012-
b's.', # SETITEM
1013-
b'Ns.',
1014-
b'NNs.',
1015-
b't.', # TUPLE
1016-
b'u.', # SETITEMS
1017-
b'(u.',
1018-
b'}(Nu.',
1019-
b'\x81.', # NEWOBJ
1020-
b')\x81.',
1021-
b'\x85.', # TUPLE1
1022-
b'\x86.', # TUPLE2
1023-
b'N\x86.',
1024-
b'\x87.', # TUPLE3
1025-
b'N\x87.',
1026-
b'NN\x87.',
1027-
b'\x90.', # ADDITEMS
1028-
# b'(\x90.', # PyUnpickler raises AttributeError
1029-
b'\x91.', # FROZENSET
1030-
b'\x92.', # NEWOBJ_EX
1031-
b')}\x92.',
1032-
b'\x93.', # STACK_GLOBAL
1033-
b'Vlist\n\x93.',
1034-
b'\x94.', # MEMOIZE
999+
b'.', # STOP
1000+
b'0', # POP
1001+
b'1', # POP_MARK
1002+
b'2', # DUP
1003+
# b'(2', # PyUnpickler doesn't raise
1004+
b'R', # REDUCE
1005+
b')R',
1006+
b'a', # APPEND
1007+
b'Na',
1008+
b'b', # BUILD
1009+
b'Nb',
1010+
b'd', # DICT
1011+
b'e', # APPENDS
1012+
# b'(e', # PyUnpickler raises AttributeError
1013+
b'ibuiltins\nlist\n', # INST
1014+
b'l', # LIST
1015+
b'o', # OBJ
1016+
b'(o',
1017+
b'p1\n', # PUT
1018+
b'q\x00', # BINPUT
1019+
b'r\x00\x00\x00\x00', # LONG_BINPUT
1020+
b's', # SETITEM
1021+
b'Ns',
1022+
b'NNs',
1023+
b't', # TUPLE
1024+
b'u', # SETITEMS
1025+
# b'(u', # PyUnpickler doesn't raise
1026+
b'}(Nu',
1027+
b'\x81', # NEWOBJ
1028+
b')\x81',
1029+
b'\x85', # TUPLE1
1030+
b'\x86', # TUPLE2
1031+
b'N\x86',
1032+
b'\x87', # TUPLE3
1033+
b'N\x87',
1034+
b'NN\x87',
1035+
b'\x90', # ADDITEMS
1036+
# b'(\x90', # PyUnpickler raises AttributeError
1037+
b'\x91', # FROZENSET
1038+
b'\x92', # NEWOBJ_EX
1039+
b')}\x92',
1040+
b'\x93', # STACK_GLOBAL
1041+
b'Vlist\n\x93',
1042+
b'\x94', # MEMOIZE
10351043
]
10361044
for p in badpickles:
1037-
with self.subTest(p):
1038-
self.assertRaises(self.bad_stack_errors, self.loads, p)
1045+
self.check_unpickling_error(self.bad_stack_errors, p)
10391046

10401047
def test_bad_mark(self):
10411048
badpickles = [
1042-
b'cbuiltins\nlist\n)(R.', # REDUCE
1043-
b'cbuiltins\nlist\n()R.',
1044-
b']N(a.', # APPEND
1045-
b'cbuiltins\nValueError\n)R}(b.', # BUILD
1046-
b'cbuiltins\nValueError\n)R(}b.',
1047-
b'(Nd.', # DICT
1048-
b'}NN(s.', # SETITEM
1049-
b'}N(Ns.',
1050-
b'cbuiltins\nlist\n)(\x81.', # NEWOBJ
1051-
b'cbuiltins\nlist\n()\x81.',
1052-
b'N(\x85.', # TUPLE1
1053-
b'NN(\x86.', # TUPLE2
1054-
b'N(N\x86.',
1055-
b'NNN(\x87.', # TUPLE3
1056-
b'NN(N\x87.',
1057-
b'N(NN\x87.',
1058-
b'cbuiltins\nlist\n)}(\x92.', # NEWOBJ_EX
1059-
b'cbuiltins\nlist\n)(}\x92.',
1060-
b'cbuiltins\nlist\n()}\x92.',
1061-
b'Vbuiltins\n(Vlist\n\x93.', # STACK_GLOBAL
1062-
b'Vbuiltins\nVlist\n(\x93.',
1049+
# b'N(.', # STOP
1050+
b'N(2', # DUP
1051+
b'cbuiltins\nlist\n)(R', # REDUCE
1052+
b'cbuiltins\nlist\n()R',
1053+
b']N(a', # APPEND
1054+
# BUILD
1055+
b'cbuiltins\nValueError\n)R}(b',
1056+
b'cbuiltins\nValueError\n)R(}b',
1057+
b'(Nd', # DICT
1058+
b'N(p1\n', # PUT
1059+
b'N(q\x00', # BINPUT
1060+
b'N(r\x00\x00\x00\x00', # LONG_BINPUT
1061+
b'}NN(s', # SETITEM
1062+
b'}N(Ns',
1063+
b'}(NNs',
1064+
b'}((u', # SETITEMS
1065+
b'cbuiltins\nlist\n)(\x81', # NEWOBJ
1066+
b'cbuiltins\nlist\n()\x81',
1067+
b'N(\x85', # TUPLE1
1068+
b'NN(\x86', # TUPLE2
1069+
b'N(N\x86',
1070+
b'NNN(\x87', # TUPLE3
1071+
b'NN(N\x87',
1072+
b'N(NN\x87',
1073+
b']((\x90', # ADDITEMS
1074+
# NEWOBJ_EX
1075+
b'cbuiltins\nlist\n)}(\x92',
1076+
b'cbuiltins\nlist\n)(}\x92',
1077+
b'cbuiltins\nlist\n()}\x92',
1078+
# STACK_GLOBAL
1079+
b'Vbuiltins\n(Vlist\n\x93',
1080+
b'Vbuiltins\nVlist\n(\x93',
1081+
b'N(\x94', # MEMOIZE
1082+
]
1083+
for p in badpickles:
1084+
self.check_unpickling_error(self.bad_mark_errors, p)
1085+
1086+
def test_truncated_data(self):
1087+
self.check_unpickling_error(EOFError, b'')
1088+
self.check_unpickling_error(EOFError, b'N')
1089+
badpickles = [
1090+
b'B', # BINBYTES
1091+
b'B\x03\x00\x00',
1092+
b'B\x03\x00\x00\x00',
1093+
b'B\x03\x00\x00\x00ab',
1094+
b'C', # SHORT_BINBYTES
1095+
b'C\x03',
1096+
b'C\x03ab',
1097+
b'F', # FLOAT
1098+
b'F0.0',
1099+
b'F0.00',
1100+
b'G', # BINFLOAT
1101+
b'G\x00\x00\x00\x00\x00\x00\x00',
1102+
b'I', # INT
1103+
b'I0',
1104+
b'J', # BININT
1105+
b'J\x00\x00\x00',
1106+
b'K', # BININT1
1107+
b'L', # LONG
1108+
b'L0',
1109+
b'L10',
1110+
b'L0L',
1111+
b'L10L',
1112+
b'M', # BININT2
1113+
b'M\x00',
1114+
# b'P', # PERSID
1115+
# b'Pabc',
1116+
b'S', # STRING
1117+
b"S'abc'",
1118+
b'T', # BINSTRING
1119+
b'T\x03\x00\x00',
1120+
b'T\x03\x00\x00\x00',
1121+
b'T\x03\x00\x00\x00ab',
1122+
b'U', # SHORT_BINSTRING
1123+
b'U\x03',
1124+
b'U\x03ab',
1125+
b'V', # UNICODE
1126+
b'Vabc',
1127+
b'X', # BINUNICODE
1128+
b'X\x03\x00\x00',
1129+
b'X\x03\x00\x00\x00',
1130+
b'X\x03\x00\x00\x00ab',
1131+
b'(c', # GLOBAL
1132+
b'(cbuiltins',
1133+
b'(cbuiltins\n',
1134+
b'(cbuiltins\nlist',
1135+
b'Ng', # GET
1136+
b'Ng0',
1137+
b'(i', # INST
1138+
b'(ibuiltins',
1139+
b'(ibuiltins\n',
1140+
b'(ibuiltins\nlist',
1141+
b'Nh', # BINGET
1142+
b'Nj', # LONG_BINGET
1143+
b'Nj\x00\x00\x00',
1144+
b'Np', # PUT
1145+
b'Np0',
1146+
b'Nq', # BINPUT
1147+
b'Nr', # LONG_BINPUT
1148+
b'Nr\x00\x00\x00',
1149+
b'\x80', # PROTO
1150+
b'\x82', # EXT1
1151+
b'\x83', # EXT2
1152+
b'\x84\x01',
1153+
b'\x84', # EXT4
1154+
b'\x84\x01\x00\x00',
1155+
b'\x8a', # LONG1
1156+
b'\x8b', # LONG4
1157+
b'\x8b\x00\x00\x00',
1158+
b'\x8c', # SHORT_BINUNICODE
1159+
b'\x8c\x03',
1160+
b'\x8c\x03ab',
1161+
b'\x8d', # BINUNICODE8
1162+
b'\x8d\x03\x00\x00\x00\x00\x00\x00',
1163+
b'\x8d\x03\x00\x00\x00\x00\x00\x00\x00',
1164+
b'\x8d\x03\x00\x00\x00\x00\x00\x00\x00ab',
1165+
b'\x8e', # BINBYTES8
1166+
b'\x8e\x03\x00\x00\x00\x00\x00\x00',
1167+
b'\x8e\x03\x00\x00\x00\x00\x00\x00\x00',
1168+
b'\x8e\x03\x00\x00\x00\x00\x00\x00\x00ab',
1169+
b'\x95', # FRAME
1170+
b'\x95\x02\x00\x00\x00\x00\x00\x00',
1171+
b'\x95\x02\x00\x00\x00\x00\x00\x00\x00',
1172+
b'\x95\x02\x00\x00\x00\x00\x00\x00\x00N',
10631173
]
10641174
for p in badpickles:
1065-
# PyUnpickler prints reduce errors to stdout
1066-
with self.subTest(p), captured_stdout():
1067-
try:
1068-
self.loads(p)
1069-
except (IndexError, AttributeError, TypeError,
1070-
pickle.UnpicklingError):
1071-
pass
1175+
self.check_unpickling_error(self.truncated_errors, p)
10721176

10731177

10741178
class AbstractPickleTests(unittest.TestCase):

0 commit comments

Comments
 (0)