From 7dd1e503edcd635f9dcf50ed2a1dcf7d2627dd7b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 29 Apr 2025 15:20:47 +0200 Subject: [PATCH 1/2] gh-130317: Fix strict aliasing in PyFloat_Pack8() * Fix strict aliasing in PyFloat_Pack8() and PyFloat_Pack4() * Fix _testcapi.float_set_snan() on x86 (32-bit). --- Modules/_testcapi/float.c | 8 ++++++-- Objects/floatobject.c | 14 +++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Modules/_testcapi/float.c b/Modules/_testcapi/float.c index 2feeb205d8a376..47a850f17be519 100644 --- a/Modules/_testcapi/float.c +++ b/Modules/_testcapi/float.c @@ -182,8 +182,12 @@ _testcapi_float_set_snan(PyObject *module, PyObject *obj) uint64_t v; memcpy(&v, &d, 8); v &= ~(1ULL << 51); /* make sNaN */ - memcpy(&d, &v, 8); - return PyFloat_FromDouble(d); + + // gh-130317: Work around 32-bit compilers which clear sNaN flag + // when calling PyFloat_FromDouble(). Set ob_fval using memcpy(). + PyObject *res = PyFloat_FromDouble(0.0); + memcpy(&((PyFloatObject *)res)->ob_fval, &v, 8); + return res; } static PyMethodDef test_methods[] = { diff --git a/Objects/floatobject.c b/Objects/floatobject.c index e0a8f0c62d4951..76ed24d29fd25c 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -2197,12 +2197,10 @@ PyFloat_Pack4(double x, char *data, int le) memcpy(&v, &x, 8); if ((v & (1ULL << 51)) == 0) { - union float_val { - float f; - uint32_t u32; - } *py = (union float_val *)&y; - - py->u32 &= ~(1 << 22); /* make sNaN */ + uint32_t u32; + memcpy(&u32, &y, 4); + u32 &= ~(1 << 22); /* make sNaN */ + memcpy(&y, &u32, 4); } } @@ -2340,7 +2338,9 @@ PyFloat_Pack8(double x, char *data, int le) return -1; } else { - const unsigned char *s = (unsigned char*)&x; + unsigned char as_bytes[8]; + memcpy(as_bytes, &x, 8); + const unsigned char *s = as_bytes; int i, incr = 1; if ((double_format == ieee_little_endian_format && !le) From 8b873f0b5d9871e691477f4c97ae19d1db27b904 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 29 Apr 2025 15:42:03 +0200 Subject: [PATCH 2/2] Change comment --- Modules/_testcapi/float.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/_testcapi/float.c b/Modules/_testcapi/float.c index 47a850f17be519..007884bc1f9da3 100644 --- a/Modules/_testcapi/float.c +++ b/Modules/_testcapi/float.c @@ -183,8 +183,7 @@ _testcapi_float_set_snan(PyObject *module, PyObject *obj) memcpy(&v, &d, 8); v &= ~(1ULL << 51); /* make sNaN */ - // gh-130317: Work around 32-bit compilers which clear sNaN flag - // when calling PyFloat_FromDouble(). Set ob_fval using memcpy(). + // gh-130317: memcpy() is needed to preserve the sNaN flag on x86 (32-bit) PyObject *res = PyFloat_FromDouble(0.0); memcpy(&((PyFloatObject *)res)->ob_fval, &v, 8); return res;