summaryrefslogtreecommitdiff
path: root/Lib/test/test_struct.py
diff options
context:
space:
mode:
authorSteve Dower <steve.dower@microsoft.com>2017-02-04 15:05:40 -0800
committerSteve Dower <steve.dower@microsoft.com>2017-02-04 15:05:40 -0800
commitb2fa705fd3887c326e811c418469c784353027f4 (patch)
treeb3428f73de91453edbfd4df1a5d4a212d182eb44 /Lib/test/test_struct.py
parent134e58fd3aaa2e91390041e143f3f0a21a60142b (diff)
parentb53654b6dbfce8318a7d4d1cdaddca7a7fec194b (diff)
downloadcpython-b2fa705fd3887c326e811c418469c784353027f4.tar.gz
Issue #29392: Prevent crash when passing invalid arguments into msvcrt module.
Diffstat (limited to 'Lib/test/test_struct.py')
-rw-r--r--Lib/test/test_struct.py128
1 files changed, 108 insertions, 20 deletions
diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py
index 9b8178f84a..be0047589c 100644
--- a/Lib/test/test_struct.py
+++ b/Lib/test/test_struct.py
@@ -1,5 +1,6 @@
from collections import abc
import array
+import math
import operator
import unittest
import struct
@@ -15,22 +16,10 @@ byteorders = '', '@', '=', '<', '>', '!'
def iter_integer_formats(byteorders=byteorders):
for code in integer_codes:
for byteorder in byteorders:
- if (byteorder in ('', '@') and code in ('q', 'Q') and
- not HAVE_LONG_LONG):
- continue
if (byteorder not in ('', '@') and code in ('n', 'N')):
continue
yield code, byteorder
-# Native 'q' packing isn't available on systems that don't have the C
-# long long type.
-try:
- struct.pack('q', 5)
-except struct.error:
- HAVE_LONG_LONG = False
-else:
- HAVE_LONG_LONG = True
-
def string_reverse(s):
return s[::-1]
@@ -158,9 +147,7 @@ class StructTest(unittest.TestCase):
self.assertEqual(size, expected_size[code])
# native integer sizes
- native_pairs = 'bB', 'hH', 'iI', 'lL', 'nN'
- if HAVE_LONG_LONG:
- native_pairs += 'qQ',
+ native_pairs = 'bB', 'hH', 'iI', 'lL', 'nN', 'qQ'
for format_pair in native_pairs:
for byteorder in '', '@':
signed_size = struct.calcsize(byteorder + format_pair[0])
@@ -173,9 +160,8 @@ class StructTest(unittest.TestCase):
self.assertLessEqual(4, struct.calcsize('l'))
self.assertLessEqual(struct.calcsize('h'), struct.calcsize('i'))
self.assertLessEqual(struct.calcsize('i'), struct.calcsize('l'))
- if HAVE_LONG_LONG:
- self.assertLessEqual(8, struct.calcsize('q'))
- self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q'))
+ self.assertLessEqual(8, struct.calcsize('q'))
+ self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q'))
self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('i'))
self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('P'))
@@ -366,8 +352,6 @@ class StructTest(unittest.TestCase):
# SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
# from the low-order discarded bits could propagate into the exponent
# field, causing the result to be wrong by a factor of 2.
- import math
-
for base in range(1, 33):
# smaller <- largest representable float less than base.
delta = 0.5
@@ -663,6 +647,110 @@ class UnpackIteratorTest(unittest.TestCase):
self.assertRaises(StopIteration, next, it)
self.assertRaises(StopIteration, next, it)
+ def test_half_float(self):
+ # Little-endian examples from:
+ # http://en.wikipedia.org/wiki/Half_precision_floating-point_format
+ format_bits_float__cleanRoundtrip_list = [
+ (b'\x00\x3c', 1.0),
+ (b'\x00\xc0', -2.0),
+ (b'\xff\x7b', 65504.0), # (max half precision)
+ (b'\x00\x04', 2**-14), # ~= 6.10352 * 10**-5 (min pos normal)
+ (b'\x01\x00', 2**-24), # ~= 5.96046 * 10**-8 (min pos subnormal)
+ (b'\x00\x00', 0.0),
+ (b'\x00\x80', -0.0),
+ (b'\x00\x7c', float('+inf')),
+ (b'\x00\xfc', float('-inf')),
+ (b'\x55\x35', 0.333251953125), # ~= 1/3
+ ]
+
+ for le_bits, f in format_bits_float__cleanRoundtrip_list:
+ be_bits = le_bits[::-1]
+ self.assertEqual(f, struct.unpack('<e', le_bits)[0])
+ self.assertEqual(le_bits, struct.pack('<e', f))
+ self.assertEqual(f, struct.unpack('>e', be_bits)[0])
+ self.assertEqual(be_bits, struct.pack('>e', f))
+ if sys.byteorder == 'little':
+ self.assertEqual(f, struct.unpack('e', le_bits)[0])
+ self.assertEqual(le_bits, struct.pack('e', f))
+ else:
+ self.assertEqual(f, struct.unpack('e', be_bits)[0])
+ self.assertEqual(be_bits, struct.pack('e', f))
+
+ # Check for NaN handling:
+ format_bits__nan_list = [
+ ('<e', b'\x01\xfc'),
+ ('<e', b'\x00\xfe'),
+ ('<e', b'\xff\xff'),
+ ('<e', b'\x01\x7c'),
+ ('<e', b'\x00\x7e'),
+ ('<e', b'\xff\x7f'),
+ ]
+
+ for formatcode, bits in format_bits__nan_list:
+ self.assertTrue(math.isnan(struct.unpack('<e', bits)[0]))
+ self.assertTrue(math.isnan(struct.unpack('>e', bits[::-1])[0]))
+
+ # Check that packing produces a bit pattern representing a quiet NaN:
+ # all exponent bits and the msb of the fraction should all be 1.
+ packed = struct.pack('<e', math.nan)
+ self.assertEqual(packed[1] & 0x7e, 0x7e)
+ packed = struct.pack('<e', -math.nan)
+ self.assertEqual(packed[1] & 0x7e, 0x7e)
+
+ # Checks for round-to-even behavior
+ format_bits_float__rounding_list = [
+ ('>e', b'\x00\x01', 2.0**-25 + 2.0**-35), # Rounds to minimum subnormal
+ ('>e', b'\x00\x00', 2.0**-25), # Underflows to zero (nearest even mode)
+ ('>e', b'\x00\x00', 2.0**-26), # Underflows to zero
+ ('>e', b'\x03\xff', 2.0**-14 - 2.0**-24), # Largest subnormal.
+ ('>e', b'\x03\xff', 2.0**-14 - 2.0**-25 - 2.0**-65),
+ ('>e', b'\x04\x00', 2.0**-14 - 2.0**-25),
+ ('>e', b'\x04\x00', 2.0**-14), # Smallest normal.
+ ('>e', b'\x3c\x01', 1.0+2.0**-11 + 2.0**-16), # rounds to 1.0+2**(-10)
+ ('>e', b'\x3c\x00', 1.0+2.0**-11), # rounds to 1.0 (nearest even mode)
+ ('>e', b'\x3c\x00', 1.0+2.0**-12), # rounds to 1.0
+ ('>e', b'\x7b\xff', 65504), # largest normal
+ ('>e', b'\x7b\xff', 65519), # rounds to 65504
+ ('>e', b'\x80\x01', -2.0**-25 - 2.0**-35), # Rounds to minimum subnormal
+ ('>e', b'\x80\x00', -2.0**-25), # Underflows to zero (nearest even mode)
+ ('>e', b'\x80\x00', -2.0**-26), # Underflows to zero
+ ('>e', b'\xbc\x01', -1.0-2.0**-11 - 2.0**-16), # rounds to 1.0+2**(-10)
+ ('>e', b'\xbc\x00', -1.0-2.0**-11), # rounds to 1.0 (nearest even mode)
+ ('>e', b'\xbc\x00', -1.0-2.0**-12), # rounds to 1.0
+ ('>e', b'\xfb\xff', -65519), # rounds to 65504
+ ]
+
+ for formatcode, bits, f in format_bits_float__rounding_list:
+ self.assertEqual(bits, struct.pack(formatcode, f))
+
+ # This overflows, and so raises an error
+ format_bits_float__roundingError_list = [
+ # Values that round to infinity.
+ ('>e', 65520.0),
+ ('>e', 65536.0),
+ ('>e', 1e300),
+ ('>e', -65520.0),
+ ('>e', -65536.0),
+ ('>e', -1e300),
+ ('<e', 65520.0),
+ ('<e', 65536.0),
+ ('<e', 1e300),
+ ('<e', -65520.0),
+ ('<e', -65536.0),
+ ('<e', -1e300),
+ ]
+
+ for formatcode, f in format_bits_float__roundingError_list:
+ self.assertRaises(OverflowError, struct.pack, formatcode, f)
+
+ # Double rounding
+ format_bits_float__doubleRoundingError_list = [
+ ('>e', b'\x67\xff', 0x1ffdffffff * 2**-26), # should be 2047, if double-rounded 64>32>16, becomes 2048
+ ]
+
+ for formatcode, bits, f in format_bits_float__doubleRoundingError_list:
+ self.assertEqual(bits, struct.pack(formatcode, f))
+
if __name__ == '__main__':
unittest.main()