https://github.com/python/cpython/commit/1db5966141a9ca736add1a9699dde926e8099b14
commit: 1db5966141a9ca736add1a9699dde926e8099b14
branch: main
author: Cody Maloney <[email protected]>
committer: gpshead <[email protected]>
date: 2026-11-03T16:47:51-08:00
summary:

gh-159184: Do not intern NaN constants on the free-threaded build (GH-161276)

compare_constants() matches floats by bits, but hash_const() uses the object
hash, which for a NaN depends on its address, so each NaN loaded by
marshal.loads() added an immortal entry to the constants table.  Hashing the
bits would merge NaNs and shrink frozensets, so leave them out of the table.

Co-authored-by: Claude Opus 5.5 <[email protected]>

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-11-03-13-44-26.gh-issue-159184.X_sOdY.rst
M Objects/codeobject.c

diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-11-03-13-44-26.gh-issue-159184.X_sOdY.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-11-03-13-44-26.gh-issue-159184.X_sOdY.rst
new file mode 100644
index 00000000000000..651ac1d0b9bae9
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-11-03-13-44-26.gh-issue-159184.X_sOdY.rst
@@ -0,0 +1,2 @@
+Fix a leak of NaN constants in code objects created by :func:`marshal.loads`
+on the free-threaded build.
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index eb390ab24ec13e..2255220bec3d30 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -173,8 +173,16 @@ should_immortalize_constant(PyObject *v)
                 _Py_IsImmortal(slice->stop) &&
                 _Py_IsImmortal(slice->step));
     }
-    return (PyLong_CheckExact(v) || PyFloat_CheckExact(v) ||
-            PyComplex_CheckExact(v) || PyBytes_CheckExact(v));
+    // The hash of a NaN depends on its address, so the table would keep every
+    // NaN object it gets (and merging them would shrink frozensets).
+    if (PyFloat_CheckExact(v)) {
+        return !isnan(PyFloat_AS_DOUBLE(v));
+    }
+    if (PyComplex_CheckExact(v)) {
+        Py_complex c = ((PyComplexObject *)v)->cval;
+        return !isnan(c.real) && !isnan(c.imag);
+    }
+    return PyLong_CheckExact(v) || PyBytes_CheckExact(v);
 }
 #endif
 

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to