From 02cd6d709709e28c7a8fa62ce3620ea000b524d3 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 29 Apr 2025 16:27:50 +0200 Subject: gh-130317: Fix strict aliasing in PyFloat_Pack8() (#133150) * Fix strict aliasing in PyFloat_Pack8() and PyFloat_Pack4(). * Fix _testcapi.float_set_snan() on x86 (32-bit). --- Modules/_testcapi/float.c | 7 +++++-- Objects/floatobject.c | 14 +++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Modules/_testcapi/float.c b/Modules/_testcapi/float.c index 2feeb20..007884b 100644 --- a/Modules/_testcapi/float.c +++ b/Modules/_testcapi/float.c @@ -182,8 +182,11 @@ _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: 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; } static PyMethodDef test_methods[] = { diff --git a/Objects/floatobject.c b/Objects/floatobject.c index e0a8f0c..76ed24d 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) -- cgit v0.12