Skip to content

Commit 8a25840

Browse files
miss-islingtonvstinnerskirpichev
authored
[3.14] gh-145633: Fix struct.pack('f') on s390x (GH-146422) (#146460)
gh-145633: Fix struct.pack('f') on s390x (GH-146422) Use PyFloat_Pack4() to raise OverflowError. Add more tests on packing/unpacking floats. (cherry picked from commit 8de70b3) Co-authored-by: Victor Stinner <vstinner@python.org> Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com>
1 parent 7efa72a commit 8a25840

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():
@@ -862,6 +877,24 @@ def test_operations_on_half_initialized_Struct(self):
862877
self.assertRaises(RuntimeError, repr, S)
863878
self.assertEqual(S.size, -1)
864879

880+
def test_float_round_trip(self):
881+
for format in (
882+
"f", "<f", ">f",
883+
"d", "<d", ">d",
884+
"e", "<e", ">e",
885+
):
886+
with self.subTest(format=format):
887+
f = struct.unpack(format, struct.pack(format, 1.5))[0]
888+
self.assertEqual(f, 1.5)
889+
f = struct.unpack(format, struct.pack(format, NAN))[0]
890+
self.assertTrue(math.isnan(f), f)
891+
f = struct.unpack(format, struct.pack(format, INF))[0]
892+
self.assertTrue(math.isinf(f), f)
893+
self.assertEqual(math.copysign(1.0, f), 1.0)
894+
f = struct.unpack(format, struct.pack(format, -INF))[0]
895+
self.assertTrue(math.isinf(f), f)
896+
self.assertEqual(math.copysign(1.0, f), -1.0)
897+
865898

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

775774
static int

0 commit comments

Comments
 (0)