From aba373ccdeb6a5e14bcfd9e452ca1b499126fbe8 Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Tue, 3 Nov 2026 13:44:39 -0800 Subject: [PATCH] gh-159184: Do not intern NaN constants on the free-threaded build 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 --- .../2026-11-03-13-44-26.gh-issue-159184.X_sOdY.rst | 2 ++ Objects/codeobject.c | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-11-03-13-44-26.gh-issue-159184.X_sOdY.rst 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 000000000000000..651ac1d0b9bae9f --- /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 eb390ab24ec13e6..2255220bec3d307 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