[Python-checkins] python/dist/src/Modules cPickle.c,2.73.2.1.2.3,2.73.2.1.2.4 structmodule.c,2.51.8.1,2.51.8.2

tim_one@users.sourceforge.net tim_one@users.sourceforge.net
Thu, 20 Mar 2003 10:31:30 -0800


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

Modified Files:
      Tag: release22-maint
	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.


Index: cPickle.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/cPickle.c,v
retrieving revision 2.73.2.1.2.3
retrieving revision 2.73.2.1.2.4
diff -C2 -d -r2.73.2.1.2.3 -r2.73.2.1.2.4
*** cPickle.c	24 Sep 2002 11:53:34 -0000	2.73.2.1.2.3
--- cPickle.c	20 Mar 2003 18:31:13 -0000	2.73.2.1.2.4
***************
*** 706,710 ****
  static int
  put(Picklerobject *self, PyObject *ob) {
!     if (ob->ob_refcnt < 2 || self->fast) 
          return 0;
  
--- 706,710 ----
  static int
  put(Picklerobject *self, PyObject *ob) {
!     if (ob->ob_refcnt < 2 || self->fast)
          return 0;
  
***************
*** 922,926 ****
  }
  
! int 
  fast_save_leave(Picklerobject *self, PyObject *obj)
  {
--- 922,926 ----
  }
  
! int
  fast_save_leave(Picklerobject *self, PyObject *obj)
  {
***************
*** 1065,1074 ****
          }
  
!         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 */
--- 1065,1070 ----
          }
  
!         if (e >= 1024)
! 	    goto Overflow;
          else if (e < -1022) {
              /* Gradual underflow */
***************
*** 1084,1090 ****
--- 1080,1103 ----
          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 */
***************
*** 1132,1135 ****
--- 1145,1153 ----
  
      return 0;
+ 
+  Overflow:
+ 	PyErr_SetString(PyExc_OverflowError,
+ 			"float too large to pack with d format");
+ 	return -1;
  }
  
***************
*** 2104,2110 ****
  static PyObject *
  Pickle_clear_memo(Picklerobject *self, PyObject *args) {
!     if (!PyArg_ParseTuple(args,":clear_memo")) 
  	return NULL;
!     if (self->memo) 
  	PyDict_Clear(self->memo);
      Py_INCREF(Py_None);
--- 2122,2128 ----
  static PyObject *
  Pickle_clear_memo(Picklerobject *self, PyObject *args) {
!     if (!PyArg_ParseTuple(args,":clear_memo"))
  	return NULL;
!     if (self->memo)
  	PyDict_Clear(self->memo);
      Py_INCREF(Py_None);
***************
*** 2121,2125 ****
  
    /* Can be called by Python code or C code */
!   if (args && !PyArg_ParseTuple(args, "|i:getvalue", &clear)) 
        return NULL;
  
--- 2139,2143 ----
  
    /* Can be called by Python code or C code */
!   if (args && !PyArg_ParseTuple(args, "|i:getvalue", &clear))
        return NULL;
  
***************
*** 2483,2487 ****
  
  static PyGetSetDef Pickler_getsets[] = {
!     {"persistent_id", (getter)Pickler_get_pers_func, 
                       (setter)Pickler_set_pers_func},
      {"inst_persistent_id", NULL, (setter)Pickler_set_inst_pers_func},
--- 2501,2505 ----
  
  static PyGetSetDef Pickler_getsets[] = {
!     {"persistent_id", (getter)Pickler_get_pers_func,
                       (setter)Pickler_set_pers_func},
      {"inst_persistent_id", NULL, (setter)Pickler_set_inst_pers_func},

Index: structmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/structmodule.c,v
retrieving revision 2.51.8.1
retrieving revision 2.51.8.2
diff -C2 -d -r2.51.8.1 -r2.51.8.2
*** structmodule.c	23 Sep 2002 20:54:04 -0000	2.51.8.1
--- structmodule.c	20 Mar 2003 18:31:20 -0000	2.51.8.2
***************
*** 226,235 ****
  	}
  
! 	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 */
--- 226,231 ----
  	}
  
! 	if (e >= 128)
! 		goto Overflow;
  	else if (e < -126) {
  		/* Gradual underflow */
***************
*** 244,247 ****
--- 240,251 ----
  	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 */
***************
*** 262,265 ****
--- 266,274 ----
  	/* Done */
  	return 0;
+ 
+  Overflow:
+ 	PyErr_SetString(PyExc_OverflowError,
+ 			"float too large to pack with f format");
+ 	return -1;
  }
  
***************
*** 297,306 ****
  	}
  
! 	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 */
--- 306,311 ----
  	}
  
! 	if (e >= 1024)
! 		goto Overflow;
  	else if (e < -1022) {
  		/* Gradual underflow */
***************
*** 316,322 ****
--- 321,342 ----
  	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 */
***************
*** 354,357 ****
--- 374,382 ----
  	/* Done */
  	return 0;
+ 
+  Overflow:
+ 	PyErr_SetString(PyExc_OverflowError,
+ 			"float too large to pack with d format");
+ 	return -1;
  }