]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-133703: dict: fix calculate_log2_keysize() (GH-133809)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Sun, 11 May 2025 07:34:15 +0000 (09:34 +0200)
committerGitHub <noreply@github.com>
Sun, 11 May 2025 07:34:15 +0000 (16:34 +0900)
(cherry picked from commit 92337f666e8a076a68305a8d6dc8bc9c095000e9)
Co-authored-by: Inada Naoki <songofacandy@gmail.com>
Lib/test/test_dict.py
Misc/NEWS.d/next/Core_and_Builtins/2025-05-10-17-12-27.gh-issue-133703.bVM-re.rst [new file with mode: 0644]
Objects/dictobject.c

index 69f1a098920b946563ba9b5d765c906d5ee301d4..10a6d071b0f50b226b40be76be250c262f3e11c7 100644 (file)
@@ -1039,10 +1039,8 @@ class DictTest(unittest.TestCase):
         a = C()
         a.x = 1
         d = a.__dict__
-        before_resize = sys.getsizeof(d)
         d[2] = 2 # split table is resized to a generic combined table
 
-        self.assertGreater(sys.getsizeof(d), before_resize)
         self.assertEqual(list(d), ['x', 2])
 
     def test_iterator_pickling(self):
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-10-17-12-27.gh-issue-133703.bVM-re.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-10-17-12-27.gh-issue-133703.bVM-re.rst
new file mode 100644 (file)
index 0000000..05bf610
--- /dev/null
@@ -0,0 +1 @@
+Fix hashtable in dict can be bigger than intended in some situations.
index 32356f0634db153de6a68d2a33856dde7ff34579..ce27e47dabf3b0368899e6cd075cb0aec30c87bb 100644 (file)
@@ -547,13 +547,13 @@ static inline uint8_t
 calculate_log2_keysize(Py_ssize_t minsize)
 {
 #if SIZEOF_LONG == SIZEOF_SIZE_T
-    minsize = (minsize | PyDict_MINSIZE) - 1;
-    return _Py_bit_length(minsize | (PyDict_MINSIZE-1));
+    minsize = Py_MAX(minsize, PyDict_MINSIZE);
+    return _Py_bit_length(minsize - 1);
 #elif defined(_MSC_VER)
-    // On 64bit Windows, sizeof(long) == 4.
-    minsize = (minsize | PyDict_MINSIZE) - 1;
+    // On 64bit Windows, sizeof(long) == 4. We cannot use _Py_bit_length.
+    minsize = Py_MAX(minsize, PyDict_MINSIZE);
     unsigned long msb;
-    _BitScanReverse64(&msb, (uint64_t)minsize);
+    _BitScanReverse64(&msb, (uint64_t)minsize - 1);
     return (uint8_t)(msb + 1);
 #else
     uint8_t log2_size;