diff options
author | Tim Peters <tim.peters@gmail.com> | 2003-03-20 18:32:13 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2003-03-20 18:32:13 (GMT) |
commit | d50ade68ec240ea8ea12604809d8c70985263dce (patch) | |
tree | 7dd938bc5a9dcf40707839e518420804bbb3cd94 /Modules/cPickle.c | |
parent | 62364ffb80a7dab0477fe7dc7aec5478ab6afec2 (diff) | |
download | cpython-d50ade68ec240ea8ea12604809d8c70985263dce.zip cpython-d50ade68ec240ea8ea12604809d8c70985263dce.tar.gz cpython-d50ade68ec240ea8ea12604809d8c70985263dce.tar.bz2 |
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.
Bugfix candidate, but I already backported this to 2.2.
In 2.3, this code remains in severe need of refactoring.
Diffstat (limited to 'Modules/cPickle.c')
-rw-r--r-- | Modules/cPickle.c | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/Modules/cPickle.c b/Modules/cPickle.c index 88f2fc1..964fc63 100644 --- a/Modules/cPickle.c +++ b/Modules/cPickle.c @@ -1156,12 +1156,8 @@ save_float(Picklerobject *self, PyObject *args) 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); @@ -1176,9 +1172,26 @@ save_float(Picklerobject *self, PyObject *args) 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); @@ -1224,6 +1237,11 @@ save_float(Picklerobject *self, PyObject *args) } return 0; + + Overflow: + PyErr_SetString(PyExc_OverflowError, + "float too large to pack with d format"); + return -1; } |