[Python-checkins] python/dist/src/Modules cPickle.c,2.140,2.141 structmodule.c,2.57,2.58

tim_one@users.sourceforge.net tim_one@users.sourceforge.net
Thu, 20 Mar 2003 10:32:18 -0800


Update of /cvsroot/python/python/dist/src/Modules
In directory sc8-pr-cvs1:/tmp/cvs-serv9471/Modules

Modified Files:
	cPickle.c structmodule.c 
Log Message:
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.


Index: cPickle.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/cPickle.c,v
retrieving revision 2.140
retrieving revision 2.141
diff -C2 -d -r2.140 -r2.141
*** cPickle.c	19 Feb 2003 01:45:13 -0000	2.140
--- cPickle.c	20 Mar 2003 18:32:08 -0000	2.141
***************
*** 1157,1166 ****
  		}
  
! 		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;
! 		}
  		else if (e < -1022) {
  			/* Gradual underflow */
--- 1157,1162 ----
  		}
  
! 		if (e >= 1024)
! 			goto Overflow;
  		else if (e < -1022) {
  			/* Gradual underflow */
***************
*** 1177,1183 ****
--- 1173,1196 ----
  		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 */
***************
*** 1225,1228 ****
--- 1238,1246 ----
  
  	return 0;
+ 
+  Overflow:
+ 	PyErr_SetString(PyExc_OverflowError,
+ 			"float too large to pack with d format");
+ 	return -1;
  }
  

Index: structmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/structmodule.c,v
retrieving revision 2.57
retrieving revision 2.58
diff -C2 -d -r2.57 -r2.58
*** structmodule.c	3 Sep 2002 18:42:21 -0000	2.57
--- structmodule.c	20 Mar 2003 18:32:13 -0000	2.58
***************
*** 225,234 ****
  	}
  
! 	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;
! 	}
  	else if (e < -126) {
  		/* Gradual underflow */
--- 225,230 ----
  	}
  
! 	if (e >= 128)
! 		goto Overflow;
  	else if (e < -126) {
  		/* Gradual underflow */
***************
*** 243,246 ****
--- 239,250 ----
  	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 */
***************
*** 261,264 ****
--- 265,273 ----
  	/* Done */
  	return 0;
+ 
+  Overflow:
+ 	PyErr_SetString(PyExc_OverflowError,
+ 			"float too large to pack with f format");
+ 	return -1;
  }
  
***************
*** 296,305 ****
  	}
  
! 	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;
! 	}
  	else if (e < -1022) {
  		/* Gradual underflow */
--- 305,310 ----
  	}
  
! 	if (e >= 1024)
! 		goto Overflow;
  	else if (e < -1022) {
  		/* Gradual underflow */
***************
*** 315,321 ****
--- 320,341 ----
  	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 */
***************
*** 353,356 ****
--- 373,381 ----
  	/* Done */
  	return 0;
+ 
+  Overflow:
+ 	PyErr_SetString(PyExc_OverflowError,
+ 			"float too large to pack with d format");
+ 	return -1;
  }