Skip to content

Commit bdff94e

Browse files
Legoclonesserhiy-storchaka
authored andcommitted
pythongh-126992: Change pickle code to base 10 for load_long and load_int (pythonGH-127042)
Co-authored-by: Serhiy Storchaka <[email protected]>
1 parent 6cc3ec9 commit bdff94e

File tree

5 files changed

+64
-9
lines changed

5 files changed

+64
-9
lines changed

Lib/pickle.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,7 +1387,7 @@ def load_int(self):
13871387
elif data == TRUE[1:]:
13881388
val = True
13891389
else:
1390-
val = int(data, 0)
1390+
val = int(data)
13911391
self.append(val)
13921392
dispatch[INT[0]] = load_int
13931393

@@ -1407,7 +1407,7 @@ def load_long(self):
14071407
val = self.readline()[:-1]
14081408
if val and val[-1] == b'L'[0]:
14091409
val = val[:-1]
1410-
self.append(int(val, 0))
1410+
self.append(int(val))
14111411
dispatch[LONG[0]] = load_long
14121412

14131413
def load_long1(self):

Lib/test/pickletester.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,26 @@ def test_constants(self):
10121012
self.assertIs(self.loads(b'I01\n.'), True)
10131013
self.assertIs(self.loads(b'I00\n.'), False)
10141014

1015+
def test_zero_padded_integers(self):
1016+
self.assertEqual(self.loads(b'I010\n.'), 10)
1017+
self.assertEqual(self.loads(b'I-010\n.'), -10)
1018+
self.assertEqual(self.loads(b'I0010\n.'), 10)
1019+
self.assertEqual(self.loads(b'I-0010\n.'), -10)
1020+
self.assertEqual(self.loads(b'L010\n.'), 10)
1021+
self.assertEqual(self.loads(b'L-010\n.'), -10)
1022+
self.assertEqual(self.loads(b'L0010\n.'), 10)
1023+
self.assertEqual(self.loads(b'L-0010\n.'), -10)
1024+
self.assertEqual(self.loads(b'L010L\n.'), 10)
1025+
self.assertEqual(self.loads(b'L-010L\n.'), -10)
1026+
1027+
def test_nondecimal_integers(self):
1028+
self.assertRaises(ValueError, self.loads, b'I0b10\n.')
1029+
self.assertRaises(ValueError, self.loads, b'I0o10\n.')
1030+
self.assertRaises(ValueError, self.loads, b'I0x10\n.')
1031+
self.assertRaises(ValueError, self.loads, b'L0b10L\n.')
1032+
self.assertRaises(ValueError, self.loads, b'L0o10L\n.')
1033+
self.assertRaises(ValueError, self.loads, b'L0x10L\n.')
1034+
10151035
def test_empty_bytestring(self):
10161036
# issue 11286
10171037
empty = self.loads(b'\x80\x03U\x00q\x00.', encoding='koi8-r')

Lib/test/test_pickletools.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,43 @@ def test_persid(self):
443443
highest protocol among opcodes = 0
444444
''')
445445

446+
def test_constants(self):
447+
self.check_dis(b"(NI00\nI01\n\x89\x88t.", '''\
448+
0: ( MARK
449+
1: N NONE
450+
2: I INT False
451+
6: I INT True
452+
10: \\x89 NEWFALSE
453+
11: \\x88 NEWTRUE
454+
12: t TUPLE (MARK at 0)
455+
13: . STOP
456+
highest protocol among opcodes = 2
457+
''')
458+
459+
def test_integers(self):
460+
self.check_dis(b"(I0\nI1\nI10\nI011\nL12\nL13L\nL014\nL015L\nt.", '''\
461+
0: ( MARK
462+
1: I INT 0
463+
4: I INT 1
464+
7: I INT 10
465+
11: I INT 11
466+
16: L LONG 12
467+
20: L LONG 13
468+
25: L LONG 14
469+
30: L LONG 15
470+
36: t TUPLE (MARK at 0)
471+
37: . STOP
472+
highest protocol among opcodes = 0
473+
''')
474+
475+
def test_nondecimal_integers(self):
476+
self.check_dis_error(b'I0b10\n.', '', 'invalid literal for int')
477+
self.check_dis_error(b'I0o10\n.', '', 'invalid literal for int')
478+
self.check_dis_error(b'I0x10\n.', '', 'invalid literal for int')
479+
self.check_dis_error(b'L0b10L\n.', '', 'invalid literal for int')
480+
self.check_dis_error(b'L0o10L\n.', '', 'invalid literal for int')
481+
self.check_dis_error(b'L0x10L\n.', '', 'invalid literal for int')
482+
446483

447484
class MiscTestCase(unittest.TestCase):
448485
def test__all__(self):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix LONG and INT opcodes to only use base 10 for string to integer conversion in :mod:`pickle`.

Modules/_pickle.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5211,16 +5211,14 @@ load_int(PickleState *state, UnpicklerObject *self)
52115211
return bad_readline(state);
52125212

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

52185217
if (errno || (*endptr != '\n' && *endptr != '\0')) {
52195218
/* Hm, maybe we've got something long. Let's try reading
52205219
* it as a Python int object. */
52215220
errno = 0;
5222-
/* XXX: Same thing about the base here. */
5223-
value = PyLong_FromString(s, NULL, 0);
5221+
value = PyLong_FromString(s, NULL, 10);
52245222
if (value == NULL) {
52255223
PyErr_SetString(PyExc_ValueError,
52265224
"could not convert string to int");
@@ -5370,8 +5368,7 @@ load_long(PickleState *state, UnpicklerObject *self)
53705368
the 'L' to be present. */
53715369
if (s[len-2] == 'L')
53725370
s[len-2] = '\0';
5373-
/* XXX: Should the base argument explicitly set to 10? */
5374-
value = PyLong_FromString(s, NULL, 0);
5371+
value = PyLong_FromString(s, NULL, 10);
53755372
if (value == NULL)
53765373
return -1;
53775374

0 commit comments

Comments
 (0)