Skip to content

Commit 8de70b3

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

File tree

3 files changed

+37
-3
lines changed

3 files changed

+37
-3
lines changed

Lib/test/test_struct.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,21 @@ def test_705836(self):
397397
big = (1 << 25) - 1
398398
big = math.ldexp(big, 127 - 24)
399399
self.assertRaises(OverflowError, struct.pack, ">f", big)
400+
self.assertRaises(OverflowError, struct.pack, "<f", big)
401+
# same for native format, see gh-145633
402+
self.assertRaises(OverflowError, struct.pack, "f", big)
403+
404+
# And for half-floats
405+
big = (1 << 11) - 1
406+
big = math.ldexp(big, 15 - 10)
407+
packed = struct.pack(">e", big)
408+
unpacked = struct.unpack(">e", packed)[0]
409+
self.assertEqual(big, unpacked)
410+
big = (1 << 12) - 1
411+
big = math.ldexp(big, 15 - 11)
412+
self.assertRaises(OverflowError, struct.pack, ">e", big)
413+
self.assertRaises(OverflowError, struct.pack, "<e", big)
414+
self.assertRaises(OverflowError, struct.pack, "e", big)
400415

401416
def test_1530559(self):
402417
for code, byteorder in iter_integer_formats():
@@ -1016,6 +1031,24 @@ def test_operations_on_half_initialized_Struct(self):
10161031
self.assertRaises(RuntimeError, repr, S)
10171032
self.assertEqual(S.size, -1)
10181033

1034+
def test_float_round_trip(self):
1035+
for format in (
1036+
"f", "<f", ">f",
1037+
"d", "<d", ">d",
1038+
"e", "<e", ">e",
1039+
):
1040+
with self.subTest(format=format):
1041+
f = struct.unpack(format, struct.pack(format, 1.5))[0]
1042+
self.assertEqual(f, 1.5)
1043+
f = struct.unpack(format, struct.pack(format, NAN))[0]
1044+
self.assertTrue(math.isnan(f), f)
1045+
f = struct.unpack(format, struct.pack(format, INF))[0]
1046+
self.assertTrue(math.isinf(f), f)
1047+
self.assertEqual(math.copysign(1.0, f), 1.0)
1048+
f = struct.unpack(format, struct.pack(format, -INF))[0]
1049+
self.assertTrue(math.isinf(f), f)
1050+
self.assertEqual(math.copysign(1.0, f), -1.0)
1051+
10191052

10201053
class UnpackIteratorTest(unittest.TestCase):
10211054
"""
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
@@ -763,14 +763,13 @@ np_halffloat(_structmodulestate *state, char *p, PyObject *v, const formatdef *f
763763
static int
764764
np_float(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
765765
{
766-
float x = (float)PyFloat_AsDouble(v);
766+
double x = PyFloat_AsDouble(v);
767767
if (x == -1 && PyErr_Occurred()) {
768768
PyErr_SetString(state->StructError,
769769
"required argument is not a float");
770770
return -1;
771771
}
772-
memcpy(p, &x, sizeof x);
773-
return 0;
772+
return PyFloat_Pack4(x, p, PY_LITTLE_ENDIAN);
774773
}
775774

776775
static int

0 commit comments

Comments
 (0)