Mercurial > cpython-lru_cache-weakref
diff Modules/structmodule.c @ 28333:eec3fd164a7d 2.2
SF bug 705836: struct.pack of floats in non-native endian order
pack_float, pack_double, save_float: All the routines for creating
IEEE-format packed representations of floats and doubles simply ignored
that rounding can (in rare cases) propagate out of a long string of
1 bits. At worst, the end-off carry can (by mistake) interfere with
the exponent value, and then unpacking yields a result wrong by a factor
of 2. In less severe cases, it can end up losing more low-order bits
than intended, or fail to catch overflow *caused* by rounding.
| author | Tim Peters <tim.peters@gmail.com> |
|---|---|
| date | Thu, 20 Mar 2003 18:31:20 +0000 |
| parents | 0b68d810a8be |
| children |
line wrap: on
line diff
--- a/Modules/structmodule.c Thu Mar 20 18:22:50 2003 +0000 +++ b/Modules/structmodule.c Thu Mar 20 18:31:20 2003 +0000 @@ -225,12 +225,8 @@ return -1; } - if (e >= 128) { - /* XXX 128 itself is reserved for Inf/NaN */ - PyErr_SetString(PyExc_OverflowError, - "float too large to pack with f format"); - return -1; - } + if (e >= 128) + goto Overflow; else if (e < -126) { /* Gradual underflow */ f = ldexp(f, 126 + e); @@ -243,6 +239,14 @@ f *= 8388608.0; /* 2**23 */ fbits = (long) floor(f + 0.5); /* Round */ + assert(fbits <= 8388608); + if (fbits >> 23) { + /* The carry propagated out of a string of 23 1 bits. */ + fbits = 0; + ++e; + if (e >= 255) + goto Overflow; + } /* First byte */ *p = (s<<7) | (e>>1); @@ -261,6 +265,11 @@ /* Done */ return 0; + + Overflow: + PyErr_SetString(PyExc_OverflowError, + "float too large to pack with f format"); + return -1; } static int @@ -296,12 +305,8 @@ return -1; } - if (e >= 1024) { - /* XXX 1024 itself is reserved for Inf/NaN */ - PyErr_SetString(PyExc_OverflowError, - "float too large to pack with d format"); - return -1; - } + if (e >= 1024) + goto Overflow; else if (e < -1022) { /* Gradual underflow */ f = ldexp(f, 1022 + e); @@ -315,9 +320,24 @@ /* fhi receives the high 28 bits; flo the low 24 bits (== 52 bits) */ f *= 268435456.0; /* 2**28 */ fhi = (long) floor(f); /* Truncate */ + assert(fhi < 268435456); + f -= (double)fhi; f *= 16777216.0; /* 2**24 */ flo = (long) floor(f + 0.5); /* Round */ + assert(flo <= 16777216); + if (flo >> 24) { + /* The carry propagated out of a string of 24 1 bits. */ + flo = 0; + ++fhi; + if (fhi >> 28) { + /* And it also progagated out of the next 28 bits. */ + fhi = 0; + ++e; + if (e >= 2047) + goto Overflow; + } + } /* First byte */ *p = (s<<7) | (e>>4); @@ -353,6 +373,11 @@ /* Done */ return 0; + + Overflow: + PyErr_SetString(PyExc_OverflowError, + "float too large to pack with d format"); + return -1; } static PyObject *
