summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/pickle.py4
-rw-r--r--Lib/test/pickletester.py20
-rw-r--r--Lib/test/test_pickletools.py37
-rw-r--r--Misc/NEWS.d/next/Library/2024-11-20-21-20-56.gh-issue-126992.RbU0FZ.rst1
-rw-r--r--Modules/_pickle.c11
5 files changed, 64 insertions, 9 deletions
diff --git a/Lib/pickle.py b/Lib/pickle.py
index 25dadb3..1920973 100644
--- a/Lib/pickle.py
+++ b/Lib/pickle.py
@@ -1387,7 +1387,7 @@ class _Unpickler:
elif data == TRUE[1:]:
val = True
else:
- val = int(data, 0)
+ val = int(data)
self.append(val)
dispatch[INT[0]] = load_int
@@ -1407,7 +1407,7 @@ class _Unpickler:
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):
diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
index cf020a4..bdc7ef6 100644
--- a/Lib/test/pickletester.py
+++ b/Lib/test/pickletester.py
@@ -1012,6 +1012,26 @@ class AbstractUnpickleTests:
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')
diff --git a/Lib/test/test_pickletools.py b/Lib/test/test_pickletools.py
index 265dc49..a178d33 100644
--- a/Lib/test/test_pickletools.py
+++ b/Lib/test/test_pickletools.py
@@ -443,6 +443,43 @@ highest protocol among opcodes = 0
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):
diff --git a/Misc/NEWS.d/next/Library/2024-11-20-21-20-56.gh-issue-126992.RbU0FZ.rst b/Misc/NEWS.d/next/Library/2024-11-20-21-20-56.gh-issue-126992.RbU0FZ.rst
new file mode 100644
index 0000000..526785f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-11-20-21-20-56.gh-issue-126992.RbU0FZ.rst
@@ -0,0 +1 @@
+Fix LONG and INT opcodes to only use base 10 for string to integer conversion in :mod:`pickle`.
diff --git a/Modules/_pickle.c b/Modules/_pickle.c
index 2696f38..599b5f9 100644
--- a/Modules/_pickle.c
+++ b/Modules/_pickle.c
@@ -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");
@@ -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;