Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Lib/pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -1387,7 +1387,7 @@ def load_int(self):
elif data == TRUE[1:]:
val = True
else:
val = int(data, 0)
val = int(data)
self.append(val)
dispatch[INT[0]] = load_int

Expand All @@ -1407,7 +1407,7 @@ def load_long(self):
val = self.readline()[:-1]
if val and val[-1] == b'L'[0]:
val = val[:-1]
self.append(int(val, 0))
self.append(int(val))
dispatch[LONG[0]] = load_long

def load_long1(self):
Expand Down
20 changes: 20 additions & 0 deletions Lib/test/pickletester.py
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,26 @@ def test_constants(self):
self.assertIs(self.loads(b'I01\n.'), True)
self.assertIs(self.loads(b'I00\n.'), False)

def test_zero_padded_integers(self):
self.assertEqual(self.loads(b'I010\n.'), 10)
self.assertEqual(self.loads(b'I-010\n.'), -10)
self.assertEqual(self.loads(b'I0010\n.'), 10)
self.assertEqual(self.loads(b'I-0010\n.'), -10)
self.assertEqual(self.loads(b'L010\n.'), 10)
self.assertEqual(self.loads(b'L-010\n.'), -10)
self.assertEqual(self.loads(b'L0010\n.'), 10)
self.assertEqual(self.loads(b'L-0010\n.'), -10)
self.assertEqual(self.loads(b'L010L\n.'), 10)
self.assertEqual(self.loads(b'L-010L\n.'), -10)

def test_nondecimal_integers(self):
self.assertRaises(ValueError, self.loads, b'I0b10\n.')
self.assertRaises(ValueError, self.loads, b'I0o10\n.')
self.assertRaises(ValueError, self.loads, b'I0x10\n.')
self.assertRaises(ValueError, self.loads, b'L0b10L\n.')
self.assertRaises(ValueError, self.loads, b'L0o10L\n.')
self.assertRaises(ValueError, self.loads, b'L0x10L\n.')

def test_empty_bytestring(self):
# issue 11286
empty = self.loads(b'\x80\x03U\x00q\x00.', encoding='koi8-r')
Expand Down
37 changes: 37 additions & 0 deletions Lib/test/test_pickletools.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,43 @@ def test_persid(self):
highest protocol among opcodes = 0
''')

def test_constants(self):
self.check_dis(b"(NI00\nI01\n\x89\x88t.", '''\
0: ( MARK
1: N NONE
2: I INT False
6: I INT True
10: \\x89 NEWFALSE
11: \\x88 NEWTRUE
12: t TUPLE (MARK at 0)
13: . STOP
highest protocol among opcodes = 2
''')

def test_integers(self):
self.check_dis(b"(I0\nI1\nI10\nI011\nL12\nL13L\nL014\nL015L\nt.", '''\
0: ( MARK
1: I INT 0
4: I INT 1
7: I INT 10
11: I INT 11
16: L LONG 12
20: L LONG 13
25: L LONG 14
30: L LONG 15
36: t TUPLE (MARK at 0)
37: . STOP
highest protocol among opcodes = 0
''')

def test_nondecimal_integers(self):
self.check_dis_error(b'I0b10\n.', '', 'invalid literal for int')
self.check_dis_error(b'I0o10\n.', '', 'invalid literal for int')
self.check_dis_error(b'I0x10\n.', '', 'invalid literal for int')
self.check_dis_error(b'L0b10L\n.', '', 'invalid literal for int')
self.check_dis_error(b'L0o10L\n.', '', 'invalid literal for int')
self.check_dis_error(b'L0x10L\n.', '', 'invalid literal for int')


class MiscTestCase(unittest.TestCase):
def test__all__(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix LONG and INT opcodes to only use base 10 for string to integer conversion in :mod:`pickle`.
11 changes: 4 additions & 7 deletions Modules/_pickle.c
Original file line number Diff line number Diff line change
Expand Up @@ -5211,16 +5211,14 @@ load_int(PickleState *state, UnpicklerObject *self)
return bad_readline(state);

errno = 0;
/* XXX: Should the base argument of strtol() be explicitly set to 10?
XXX(avassalotti): Should this uses PyOS_strtol()? */
x = strtol(s, &endptr, 0);
/* XXX(avassalotti): Should this uses PyOS_strtol()? */
x = strtol(s, &endptr, 10);

if (errno || (*endptr != '\n' && *endptr != '\0')) {
/* Hm, maybe we've got something long. Let's try reading
* it as a Python int object. */
errno = 0;
/* XXX: Same thing about the base here. */
value = PyLong_FromString(s, NULL, 0);
value = PyLong_FromString(s, NULL, 10);
if (value == NULL) {
PyErr_SetString(PyExc_ValueError,
"could not convert string to int");
Expand Down Expand Up @@ -5370,8 +5368,7 @@ load_long(PickleState *state, UnpicklerObject *self)
the 'L' to be present. */
if (s[len-2] == 'L')
s[len-2] = '\0';
/* XXX: Should the base argument explicitly set to 10? */
value = PyLong_FromString(s, NULL, 0);
value = PyLong_FromString(s, NULL, 10);
if (value == NULL)
return -1;

Expand Down
Loading