]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-46361: Fix "small" `int` caching (GH-30583)
authorBrandt Bucher <brandt@python.org>
Sun, 16 Jan 2022 16:06:37 +0000 (08:06 -0800)
committerGitHub <noreply@github.com>
Sun, 16 Jan 2022 16:06:37 +0000 (16:06 +0000)
Lib/test/test_decimal.py
Lib/test/test_long.py
Misc/NEWS.d/next/Core and Builtins/2022-01-12-17-15-17.bpo-46361.mgI_j_.rst [new file with mode: 0644]
Modules/_decimal/_decimal.c
Objects/longobject.c

index b6173a5ffec96c46e24fba6d36d410ed89592fa3..9ced801afc2e9215c853361f9b5ecc40117c0bcf 100644 (file)
@@ -2552,6 +2552,13 @@ class PythonAPItests(unittest.TestCase):
         self.assertRaises(OverflowError, int, Decimal('inf'))
         self.assertRaises(OverflowError, int, Decimal('-inf'))
 
+    @cpython_only
+    def test_small_ints(self):
+        Decimal = self.decimal.Decimal
+        # bpo-46361
+        for x in range(-5, 257):
+            self.assertIs(int(Decimal(x)), x)
+
     def test_trunc(self):
         Decimal = self.decimal.Decimal
 
index f2a622b5868f0851956469f1b5ee053a6753e335..c7dd0b274d1e372df1a1a58b6936a086c98b07fb 100644 (file)
@@ -1471,6 +1471,13 @@ class LongTest(unittest.TestCase):
         self.assertEqual(i, 1)
         self.assertEqual(getattr(i, 'foo', 'none'), 'bar')
 
+    @support.cpython_only
+    def test_from_bytes_small(self):
+        # bpo-46361
+        for i in range(-5, 257):
+            b = i.to_bytes(2, signed=True)
+            self.assertIs(int.from_bytes(b, signed=True), i)
+
     def test_access_to_nonexistent_digit_0(self):
         # http://bugs.python.org/issue14630: A bug in _PyLong_Copy meant that
         # ob_digit[0] was being incorrectly accessed for instances of a
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-01-12-17-15-17.bpo-46361.mgI_j_.rst b/Misc/NEWS.d/next/Core and Builtins/2022-01-12-17-15-17.bpo-46361.mgI_j_.rst
new file mode 100644 (file)
index 0000000..eef877d
--- /dev/null
@@ -0,0 +1,2 @@
+Ensure that "small" integers created by :meth:`int.from_bytes` and
+:class:`decimal.Decimal` are properly cached.
index 7fc7315603e7add91fb433e9a4d3f735d2175c81..35a115676a71bee9b4d1830d0039f79c9d56cccf 100644 (file)
@@ -3394,6 +3394,13 @@ dec_as_long(PyObject *dec, PyObject *context, int round)
         return NULL;
     }
 
+    if (n == 1) {
+        sdigit val = mpd_arith_sign(x) * ob_digit[0];
+        mpd_free(ob_digit);
+        mpd_del(x);
+        return PyLong_FromLong(val);
+    }
+
     assert(n > 0);
     pylong = _PyLong_New(n);
     if (pylong == NULL) {
index 5d181aa0850aa8bf1c3f9e64c2ed144e33ac522e..1b2d1266c6bc5f33766f36a78428890bd9694a0a 100644 (file)
@@ -911,7 +911,7 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n,
     }
 
     Py_SET_SIZE(v, is_signed ? -idigit : idigit);
-    return (PyObject *)long_normalize(v);
+    return (PyObject *)maybe_small_long(long_normalize(v));
 }
 
 int