Skip to content

Commit f3be08a

Browse files
gh-154568: Fix array unpickling of little-endian float16 (#154569)
Fix array._array_reconstructor() ignoring requested byte order for float16. The slow-path decoder for IEEE_754_FLOAT16_LE/BE computed the byte-order flag by comparing mformat_code against IEEE_754_FLOAT_LE (the 32-bit float constant) instead of IEEE_754_FLOAT16_LE. Since the float16 mformat codes are never equal to that constant, the comparison was always false, so the decoder always treated input as big-endian regardless of what was requested. Adds a regression test.
1 parent fcfa919 commit f3be08a

3 files changed

Lines changed: 16 additions & 1 deletion

File tree

Lib/test/test_array.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,10 @@ def test_numbers(self):
209209
[-1<<63, (1<<63)-1, 0]),
210210
(['l'], SIGNED_INT64_BE, '>qqq',
211211
[-1<<63, (1<<63)-1, 0]),
212+
(['e'], IEEE_754_FLOAT16_LE, '<eeee',
213+
[1.0, float('inf'), float('-inf'), -0.0]),
214+
(['e'], IEEE_754_FLOAT16_BE, '>eeee',
215+
[1.0, float('inf'), float('-inf'), -0.0]),
212216
(['f'], IEEE_754_FLOAT_LE, '<ffff',
213217
[16711938.0, float('inf'), float('-inf'), -0.0]),
214218
(['f'], IEEE_754_FLOAT_BE, '>ffff',
@@ -239,6 +243,16 @@ def test_numbers(self):
239243
self.assertEqual(a, b,
240244
msg="{0!r} != {1!r}; testcase={2!r}".format(a, b, testcase))
241245

246+
def test_float16_endianness(self):
247+
# gh-154568: array_reconstructor() slow-path decoder for
248+
# IEEE_754_FLOAT16_LE ignored the encoding.
249+
le_bytes = struct.pack('<e', 1.5)
250+
be_bytes = struct.pack('>e', 1.5)
251+
b_le = array_reconstructor(array.array, 'd', IEEE_754_FLOAT16_LE, le_bytes)
252+
b_be = array_reconstructor(array.array, 'd', IEEE_754_FLOAT16_BE, be_bytes)
253+
self.assertEqual(b_le.tolist(), [1.5])
254+
self.assertEqual(b_be.tolist(), [1.5])
255+
242256
def test_unicode(self):
243257
teststr = "Bonne Journ\xe9e \U0002030a\U00020347"
244258
testcases = (
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix :mod:`array` unpickling of little-endian float16.

Modules/arraymodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2281,7 +2281,7 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype,
22812281
case IEEE_754_FLOAT16_LE:
22822282
case IEEE_754_FLOAT16_BE: {
22832283
Py_ssize_t i;
2284-
int le = (mformat_code == IEEE_754_FLOAT_LE) ? 1 : 0;
2284+
int le = (mformat_code == IEEE_754_FLOAT16_LE) ? 1 : 0;
22852285
Py_ssize_t itemcount = Py_SIZE(items) / 2;
22862286
const char *memstr = PyBytes_AS_STRING(items);
22872287

0 commit comments

Comments
 (0)