https://github.com/python/cpython/commit/a2be2bf8535bf93fe6c0c28ca64f56df9ca4b80a commit: a2be2bf8535bf93fe6c0c28ca64f56df9ca4b80a branch: 3.14 author: Miss Islington (bot) <[email protected]> committer: gpshead <[email protected]> date: 2026-11-05T14:05:17-08:00 summary:
[3.14] gh-159184: Do not intern NaN constants on the free-threaded build (GH-161276) (#161286) 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. (cherry picked from commit 1db5966141a9ca736add1a9699dde926e8099b14) Co-authored-by: Cody Maloney <[email protected]> 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 63d127838834b3..a696b25bedd091 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]
