[gs-cvs] rev 7593 - trunk/gs/src

lpd at ghostscript.com lpd at ghostscript.com
Tue Jan 9 18:15:52 PST 2007


Author: lpd
Date: 2007-01-09 18:15:52 -0800 (Tue, 09 Jan 2007)
New Revision: 7593

Modified:
   trunk/gs/src/ibnum.c
   trunk/gs/src/ibnum.h
   trunk/gs/src/iscanbin.c
Log:
Adds some PLRM-required but formerly missing legality checks for binary
object sequences, mostly for the benefit of PS3 CET 23-32-2.


Modified: trunk/gs/src/ibnum.c
===================================================================
--- trunk/gs/src/ibnum.c	2007-01-09 23:41:08 UTC (rev 7592)
+++ trunk/gs/src/ibnum.c	2007-01-10 02:15:52 UTC (rev 7593)
@@ -143,8 +143,15 @@
 		return t_real;
 	    }
 	case num_float:
-	    np->value.realval = sdecodefloat(str, format);
-	    return t_real;
+	    {
+		float fval;
+		int code = sdecode_float(str, format, &fval);
+
+		if (code < 0)
+		    return code;
+		np->value.realval = fval;
+		return t_real;
+	    }
 	default:
 	    return_error(e_syntaxerror);	/* invalid format?? */
     }
@@ -187,21 +194,25 @@
 }
 
 /* Decode a float.  We assume that native floats occupy 32 bits. */
-float
-sdecodefloat(const byte * p, int format)
+/* If the float is an IEEE NaN or Inf, return e_undefinedresult. */
+int
+sdecode_float(const byte * p, int format, float *pfnum)
 {
     bits32 lnum;
-    float fnum;
 
     if ((format & ~(num_msb | num_lsb)) == num_float_native) {
 	/*
 	 * Just read 4 bytes and interpret them as a float, ignoring
 	 * any indication of byte ordering.
 	 */
-	memcpy(&lnum, p, 4);
-	fnum = *(float *)&lnum;
+	memcpy(pfnum, p, 4);
+#if !ARCH_FLOATS_ARE_IEEE
+	return 0;		/* no way to check for anomalies */
+#endif
+	lnum = *(bits32 *)pfnum;
     } else {
 	lnum = (bits32) sdecodelong(p, format);
+
 #if !ARCH_FLOATS_ARE_IEEE
 	{
 	    /* We know IEEE floats take 32 bits. */
@@ -209,19 +220,31 @@
 	    int sign_expt = lnum >> 23;
 	    int expt = sign_expt & 0xff;
 	    long mant = lnum & 0x7fffff;
+	    float fnum;
 
 	    if (expt == 0 && mant == 0)
 		fnum = 0;
+	    else if (expt == 0xff)
+		return_error(e_undefinedresult); /* Inf or NaN */
 	    else {
 		mant += 0x800000;
 		fnum = (float)ldexp((float)mant, expt - 127 - 23);
 	    }
 	    if (sign_expt & 0x100)
 		fnum = -fnum;
+	    *pfnum = fnum;
+	    return 0;		/* checked for Infs and NaNs above */
 	}
 #else
-	    fnum = *(float *)&lnum;
+	*pfnum = *(float *)&lnum;
 #endif
     }
-    return fnum;
+    /*
+     * Unfortunately, there is no portable way for testing whether a float
+     * is a NaN or Inf.  Do it "by hand" if the input representation is
+     * IEEE (which is the case if control arrives here).
+     */
+    if (!(~lnum & 0x7f800000))	/* i.e. exponent all 1's */
+	return_error(e_undefinedresult); /* Inf or NaN */
+    return 0;
 }

Modified: trunk/gs/src/ibnum.h
===================================================================
--- trunk/gs/src/ibnum.h	2007-01-09 23:41:08 UTC (rev 7592)
+++ trunk/gs/src/ibnum.h	2007-01-10 02:15:52 UTC (rev 7593)
@@ -73,6 +73,6 @@
 int sdecodeshort(const byte *, int);
 uint sdecodeushort(const byte *, int);
 long sdecodelong(const byte *, int);
-float sdecodefloat(const byte *, int);
+int sdecode_float(const byte *, int, float *);
 
 #endif /* ibnum_INCLUDED */

Modified: trunk/gs/src/iscanbin.c
===================================================================
--- trunk/gs/src/iscanbin.c	2007-01-09 23:41:08 UTC (rev 7592)
+++ trunk/gs/src/iscanbin.c	2007-01-10 02:15:52 UTC (rev 7593)
@@ -194,8 +194,8 @@
 		    size = sdecodeushort(p + 2, num_format);
 		    hsize = 4;
 		}
-		if (size < hsize)
-		    return_error(e_syntaxerror);
+		if (size < hsize || (size - hsize) >> 3 < top_size)
+		    return_error(e_syntaxerror); /* size too small */
 		/*
 		 * Preallocate an array large enough for the worst case,
 		 * namely, all objects and no strings.  Note that we must
@@ -360,9 +360,10 @@
 private int
 scan_bin_get_name(const gs_memory_t *mem, const ref *pnames /*t_array*/, int index, ref *pref)
 {
-    if (pnames == 0)
-	return_error(e_rangecheck);
-    return array_get(mem, pnames, (long)index, pref);
+    /* Convert all errors to e_undefined to match Adobe. */
+    if (pnames == 0 || array_get(mem, pnames, (long)index, pref) < 0)
+	return_error(e_undefined);
+    return 0;
 }
 
 /* Continue collecting a binary string. */
@@ -468,32 +469,45 @@
 	if (p[2] != 0) /* reserved, must be 0 */
 	    return_error(e_syntaxerror);
 	attrs = (p[1] & 128 ? a_executable : 0);
+	/*
+	 * We always decode all 8 bytes of the object, so we can signal
+	 * syntaxerror if any unused field is non-zero (per PLRM).
+	 */
+  	osize = sdecodeushort(p + 3, num_format);
+	value = sdecodelong(p + 5, num_format);
 	switch (p[1] & 0x7f) {
 	    case BS_TYPE_NULL:
+		if (osize | value) /* unused */
+		    return_error(e_syntaxerror);
 		make_null(op);
 		break;
 	    case BS_TYPE_INTEGER:
-		make_int(op, sdecodelong(p + 5, num_format));
+		if (osize)	/* unused */
+		    return_error(e_syntaxerror);
+		make_int(op, value);
 		break;
 	    case BS_TYPE_REAL:{
 		    float vreal;
 
-		    osize = sdecodeushort(p + 3, num_format);
 		    if (osize != 0) {	/* fixed-point number */
-			value = sdecodelong(p + 5, num_format);
+			if (osize > 31)
+			    return_error(e_syntaxerror);
 			/* ldexp requires a signed 2nd argument.... */
 			vreal = (float)ldexp((double)value, -(int)osize);
 		    } else {
-			vreal = sdecodefloat(p + 5, num_format);
+			code = sdecode_float(p + 5, num_format, &vreal);
+			if (code < 0)
+			    return code;
 		    }
 		    make_real(op, vreal);
 		    break;
 		}
 	    case BS_TYPE_BOOLEAN:
-		make_bool(op, sdecodelong(p + 5, num_format) != 0);
+		if (osize)	/* unused */
+		    return_error(e_syntaxerror);
+		make_bool(op, value != 0);
 		break;
 	    case BS_TYPE_STRING:
-		osize = sdecodeushort(p + 3, num_format);
 		attrs |= a_all;
 	      str:
 		if (osize == 0) {
@@ -502,7 +516,6 @@
 		    make_empty_string(op, attrs);
 		    break;
 		}
-		value = sdecodelong(p + 5, num_format);
 		if (value < max_array_index * SIZEOF_BIN_SEQ_OBJ ||
 		    value + osize > size
 		    )
@@ -533,8 +546,6 @@
 		attrs |= a_readonly;	/* mark as executable for later */
 		/* falls through */
 	    case BS_TYPE_NAME:
-		osize = sdecodeushort(p + 3, num_format);
-		value = sdecodelong(p + 5, num_format);
 		switch (osize) {
 		    case 0:
 			if (user_names_p == NULL)
@@ -555,10 +566,8 @@
 		}
 		break;
 	    case BS_TYPE_ARRAY:
-		osize = sdecodeushort(p + 3, num_format);
 		atype = t_array;
 	      arr:
-		value = sdecodelong(p + 5, num_format);
 		if (value + osize > min_string_index ||
 		    value & (SIZEOF_BIN_SEQ_OBJ - 1)
 		    )
@@ -574,12 +583,13 @@
 		}
 		break;
 	    case BS_TYPE_DICTIONARY:	/* EXTENSION */
-		osize = sdecodeushort(p + 3, num_format);
 		if ((osize & 1) != 0 && osize != 1)
 		    return_error(e_syntaxerror);
 		atype = t_mixedarray;	/* mark as dictionary */
 		goto arr;
 	    case BS_TYPE_MARK:
+		if (osize | value) /* unused */
+		    return_error(e_syntaxerror);
 		make_mark(op);
 		break;
 	    default:



More information about the gs-cvs mailing list