Skip to content

Commit 921515f

Browse files
vstinnerskirpichev
andauthored
[3.13] gh-145633: Fix struct.pack('f') on s390x (#146422) (#146461)
gh-145633: Fix struct.pack('f') on s390x (#146422) Use PyFloat_Pack4() to raise OverflowError. Add more tests on packing/unpacking floats. (cherry picked from commit 8de70b3) Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com>
1 parent fc4b422 commit 921515f

File tree

3 files changed

+40
-3
lines changed

3 files changed

+40
-3
lines changed

Lib/test/test_struct.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,21 @@ def test_705836(self):
392392
big = (1 << 25) - 1
393393
big = math.ldexp(big, 127 - 24)
394394
self.assertRaises(OverflowError, struct.pack, ">f", big)
395+
self.assertRaises(OverflowError, struct.pack, "<f", big)
396+
# same for native format, see gh-145633
397+
self.assertRaises(OverflowError, struct.pack, "f", big)
398+
399+
# And for half-floats
400+
big = (1 << 11) - 1
401+
big = math.ldexp(big, 15 - 10)
402+
packed = struct.pack(">e", big)
403+
unpacked = struct.unpack(">e", packed)[0]
404+
self.assertEqual(big, unpacked)
405+
big = (1 << 12) - 1
406+
big = math.ldexp(big, 15 - 11)
407+
self.assertRaises(OverflowError, struct.pack, ">e", big)
408+
self.assertRaises(OverflowError, struct.pack, "<e", big)
409+
self.assertRaises(OverflowError, struct.pack, "e", big)
395410

396411
def test_1530559(self):
397412
for code, byteorder in iter_integer_formats():
@@ -832,6 +847,27 @@ def test_operations_on_half_initialized_Struct(self):
832847
self.assertRaises(RuntimeError, repr, S)
833848
self.assertEqual(S.size, -1)
834849

850+
def test_float_round_trip(self):
851+
INF = float('inf')
852+
NAN = float('nan')
853+
854+
for format in (
855+
"f", "<f", ">f",
856+
"d", "<d", ">d",
857+
"e", "<e", ">e",
858+
):
859+
with self.subTest(format=format):
860+
f = struct.unpack(format, struct.pack(format, 1.5))[0]
861+
self.assertEqual(f, 1.5)
862+
f = struct.unpack(format, struct.pack(format, NAN))[0]
863+
self.assertTrue(math.isnan(f), f)
864+
f = struct.unpack(format, struct.pack(format, INF))[0]
865+
self.assertTrue(math.isinf(f), f)
866+
self.assertEqual(math.copysign(1.0, f), 1.0)
867+
f = struct.unpack(format, struct.pack(format, -INF))[0]
868+
self.assertTrue(math.isinf(f), f)
869+
self.assertEqual(math.copysign(1.0, f), -1.0)
870+
835871

836872
class UnpackIteratorTest(unittest.TestCase):
837873
"""
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix ``struct.pack('f', float)``: use :c:func:`PyFloat_Pack4` to raise
2+
:exc:`OverflowError`. Patch by Sergey B Kirpichev and Victor Stinner.

Modules/_struct.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -768,14 +768,13 @@ np_halffloat(_structmodulestate *state, char *p, PyObject *v, const formatdef *f
768768
static int
769769
np_float(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
770770
{
771-
float x = (float)PyFloat_AsDouble(v);
771+
double x = PyFloat_AsDouble(v);
772772
if (x == -1 && PyErr_Occurred()) {
773773
PyErr_SetString(state->StructError,
774774
"required argument is not a float");
775775
return -1;
776776
}
777-
memcpy(p, (char *)&x, sizeof x);
778-
return 0;
777+
return PyFloat_Pack4(x, p, PY_LITTLE_ENDIAN);
779778
}
780779

781780
static int

0 commit comments

Comments
 (0)