diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 947bf15439e6b36d56eff8b846a41fe1d6313c9e..b46441a5dd475f583bd95003ec0f26fdda7358bc 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,16 @@ +2004-02-28 Guilhem Lavaux <guilhem@kaffe.org> + + * java/io/ObjectInputStream.java + (readClassDescriptor): Keep elements of the mapping non null. + (checkTypeConsistency): New method. + (readFields): Fixed main loop and base logic. Small reindentation. + * java/io/ObjectStreamField.java + (lookupField): New method to update the field reference. + (checkFieldType): New method. + * java/io/ObjectStreamClass.java + (setClass, setFields): Call lookupField when building the field + database. Check the real field type. + 2004-02-28 Michael Koch <konqueror@gmx.de> * java/nio/ByteOrder.java diff --git a/libjava/java/io/ObjectInputStream.java b/libjava/java/io/ObjectInputStream.java index ce2d0ca90e26f10bc0e882413b11a4d620ab0a4e..3c2dec97010d534f8c6010558a31c172e67fce21 100644 --- a/libjava/java/io/ObjectInputStream.java +++ b/libjava/java/io/ObjectInputStream.java @@ -1,6 +1,5 @@ /* ObjectInputStream.java -- Class used to read serialized objects - Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 - Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -412,6 +411,64 @@ public class ObjectInputStream extends InputStream return ret_val; } + /** + * This method makes a partial check of types for the fields + * contained given in arguments. It checks primitive types of + * fields1 against non primitive types of fields2. This method + * assumes the two lists has already been sorted according to + * the Java specification. + * + * @param name Name of the class owning the given fields. + * @param fields1 First list to check. + * @param fields2 Second list to check. + * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present + * in the non primitive part in fields2. + */ + private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2) + throws InvalidClassException + int nonPrimitive = 0; + + for (nonPrimitive = 0; + nonPrimitive < fields1.length + && fields1[nonPrimitive].isPrimitive(); nonPrimitive++) + { + } + + if (nonPrimitive == fields1.length) + return; + + int i = 0; + ObjectStreamField f1; + ObjectStreamField f2; + + while (i < fields2.length + && nonPrimitive < fields1.length) + { + f1 = fields1[nonPrimitive]; + f2 = fields2[i]; + + if (!f2.isPrimitive()) + break; + + int compVal = f1.getName().compareTo (f2.getName()); + + if (compVal < 0) + { + nonPrimitive++; + } + else if (compVal > 0) + { + i++; + } + else + { + throw new InvalidClassException + ("invalid field type for " + f2.getName() + + " in class " + name); + } + } + } + /** * This method reads a class descriptor from the real input stream * and use these data to create a new instance of ObjectStreamClass. @@ -497,6 +554,15 @@ public class ObjectInputStream extends InputStream int real_idx = 0; int map_idx = 0; + /* + * Check that there is no type inconsistencies between the lists. + * A special checking must be done for the two groups: primitive types and + * not primitive types. + */ + checkTypeConsistency(name, real_fields, stream_fields); + checkTypeConsistency(name, stream_fields, real_fields); + + while (stream_idx < stream_fields.length || real_idx < real_fields.length) { @@ -514,7 +580,7 @@ public class ObjectInputStream extends InputStream else { int comp_val = - real_fields[real_idx].compareTo (stream_fields[stream_idx]); + real_fields[real_idx].compareTo (stream_fields[stream_idx]); if (comp_val < 0) { @@ -528,21 +594,13 @@ public class ObjectInputStream extends InputStream { stream_field = stream_fields[stream_idx++]; real_field = real_fields[real_idx++]; - if(stream_field.getType() != real_field.getType()) - throw new InvalidClassException - ("invalid field type for " + real_field.getName() + - " in class " + name); + if (stream_field.getType() != real_field.getType()) + throw new InvalidClassException + ("invalid field type for " + real_field.getName() + + " in class " + name); } } - if (stream_field != null) - { - if (stream_field.getOffset() < 0) - stream_field = null; - else if (!stream_field.isToSet()) - real_field = null; - } - if (real_field != null && !real_field.isToSet()) - real_field = null; + /* If some of stream_fields does not correspond to any of real_fields, * or the opposite, then fieldmapping will go short. */ @@ -551,7 +609,7 @@ public class ObjectInputStream extends InputStream ObjectStreamField[] newfieldmapping = new ObjectStreamField[fieldmapping.length + 2]; System.arraycopy(fieldmapping, 0, - newfieldmapping, 0, fieldmapping.length); + newfieldmapping, 0, fieldmapping.length); fieldmapping = newfieldmapping; } fieldmapping[map_idx++] = stream_field; @@ -1577,121 +1635,119 @@ public class ObjectInputStream extends InputStream { ObjectStreamField stream_field = fields[i]; ObjectStreamField real_field = fields[i + 1]; - if(stream_field != null || real_field != null) - { - boolean read_value = stream_field != null; - boolean set_value = real_field != null; - String field_name; - char type; - if (stream_field != null) - { - field_name = stream_field.getName(); - type = stream_field.getTypeCode(); - } - else - { - field_name = real_field.getName(); - type = real_field.getTypeCode(); - } + boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet()); + boolean set_value = (real_field != null && real_field.isToSet()); + String field_name; + char type; - switch(type) - { - case 'Z': - { - boolean value = - read_value ? this.realInputStream.readBoolean() : false; - if (dump && read_value && set_value) - dumpElementln(" " + field_name + ": " + value); - if (set_value) - real_field.setBooleanField(obj, value); - break; - } - case 'B': - { - byte value = - read_value ? this.realInputStream.readByte() : 0; - if (dump && read_value && set_value) - dumpElementln(" " + field_name + ": " + value); - if (set_value) - real_field.setByteField(obj, value); - break; - } - case 'C': - { - char value = - read_value ? this.realInputStream.readChar(): 0; - if (dump && read_value && set_value) - dumpElementln(" " + field_name + ": " + value); - if (set_value) - real_field.setCharField(obj, value); - break; - } - case 'D': - { - double value = - read_value ? this.realInputStream.readDouble() : 0; - if (dump && read_value && set_value) - dumpElementln(" " + field_name + ": " + value); - if (set_value) - real_field.setDoubleField(obj, value); - break; - } - case 'F': - { - float value = - read_value ? this.realInputStream.readFloat() : 0; - if (dump && read_value && set_value) - dumpElementln(" " + field_name + ": " + value); - if (set_value) - real_field.setFloatField(obj, value); - break; - } - case 'I': - { - int value = - read_value ? this.realInputStream.readInt() : 0; - if (dump && read_value && set_value) - dumpElementln(" " + field_name + ": " + value); - if (set_value) - real_field.setIntField(obj, value); - break; - } - case 'J': - { - long value = - read_value ? this.realInputStream.readLong() : 0; - if (dump && read_value && set_value) - dumpElementln(" " + field_name + ": " + value); - if (set_value) - real_field.setLongField(obj, value); - break; - } - case 'S': - { - short value = - read_value ? this.realInputStream.readShort() : 0; - if (dump && read_value && set_value) - dumpElementln(" " + field_name + ": " + value); - if (set_value) - real_field.setShortField(obj, value); - break; - } - case 'L': - case '[': - { - Object value = - read_value ? readObject() : null; - if (set_value) - real_field.setObjectField(obj, value); - break; - } - default: - throw new InternalError("Invalid type code: " + type); - } + if (stream_field != null) + { + field_name = stream_field.getName(); + type = stream_field.getTypeCode(); + } + else + { + field_name = real_field.getName(); + type = real_field.getTypeCode(); + } + + switch(type) + { + case 'Z': + { + boolean value = + read_value ? this.realInputStream.readBoolean() : false; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setBooleanField(obj, value); + break; + } + case 'B': + { + byte value = + read_value ? this.realInputStream.readByte() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setByteField(obj, value); + break; + } + case 'C': + { + char value = + read_value ? this.realInputStream.readChar(): 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setCharField(obj, value); + break; + } + case 'D': + { + double value = + read_value ? this.realInputStream.readDouble() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setDoubleField(obj, value); + break; + } + case 'F': + { + float value = + read_value ? this.realInputStream.readFloat() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setFloatField(obj, value); + break; + } + case 'I': + { + int value = + read_value ? this.realInputStream.readInt() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setIntField(obj, value); + break; + } + case 'J': + { + long value = + read_value ? this.realInputStream.readLong() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setLongField(obj, value); + break; + } + case 'S': + { + short value = + read_value ? this.realInputStream.readShort() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setShortField(obj, value); + break; + } + case 'L': + case '[': + { + Object value = + read_value ? readObject() : null; + if (set_value) + real_field.setObjectField(obj, value); + break; + } + default: + throw new InternalError("Invalid type code: " + type); } } } - + // Toggles writing primitive data to block-data buffer. private boolean setBlockDataMode (boolean on) { diff --git a/libjava/java/io/ObjectStreamClass.java b/libjava/java/io/ObjectStreamClass.java index 429db187b4752805f859c045c43be289c9348051..d080f280ba907a591ba9a6bd612b69066ec1c032 100644 --- a/libjava/java/io/ObjectStreamClass.java +++ b/libjava/java/io/ObjectStreamClass.java @@ -327,7 +327,7 @@ public class ObjectStreamClass implements Serializable i = 0; j = 0; k = 0; while (i < fields.length && j < exportedFields.length) { - int comp = fields[i].getName().compareTo(exportedFields[j].getName()); + int comp = fields[i].compareTo(exportedFields[j]); if (comp < 0) { @@ -344,10 +344,27 @@ public class ObjectStreamClass implements Serializable newFieldList[k] = exportedFields[j]; newFieldList[k].setPersistent(true); newFieldList[k].setToSet(false); + try + { + newFieldList[k].lookupField(clazz); + newFieldList[k].checkFieldType(); + } + catch (NoSuchFieldException _) + { + } j++; } else { + try + { + exportedFields[j].lookupField(clazz); + exportedFields[j].checkFieldType(); + } + catch (NoSuchFieldException _) + { + } + if (!fields[i].getType().equals(exportedFields[j].getType())) throw new InvalidClassException ("serialPersistentFields must be compatible with" + @@ -554,6 +571,19 @@ outer: if (fields != null) { Arrays.sort (fields); + // Retrieve field reference. + for (int i=0; i < fields.length; i++) + { + try + { + fields[i].lookupField(cl); + } + catch (NoSuchFieldException _) + { + fields[i].setToSet(false); + } + } + calculateOffsets(); return; } @@ -798,7 +828,7 @@ outer: fieldsArray = new ObjectStreamField[ o.length ]; System.arraycopy(o, 0, fieldsArray, 0, o.length); - + return fieldsArray; } diff --git a/libjava/java/io/ObjectStreamField.java b/libjava/java/io/ObjectStreamField.java index 603fe30917d2581978edc414739a8d10f8d73fe0..f4a866ed06753867b6e87a9b4998181aeff37fc0 100644 --- a/libjava/java/io/ObjectStreamField.java +++ b/libjava/java/io/ObjectStreamField.java @@ -41,6 +41,8 @@ package java.io; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import gnu.java.lang.reflect.TypeSignature; +import java.security.AccessController; +import java.security.PrivilegedAction; /** * This class intends to describe the field of a class for the serialization @@ -99,7 +101,7 @@ public class ObjectStreamField implements Comparable /** * There are many cases you can not get java.lang.Class from typename - * if your context class loader cann not load it, then use typename to + * if your context class loader cannot load it, then use typename to * construct the field. * * @param name Name of the field to export. @@ -292,7 +294,7 @@ public class ObjectStreamField implements Comparable } /** - * This methods returns true if the field is marked as to be + * This method returns true if the field is marked as to be * set. * * @return True if it is to be set, false in the other cases. @@ -303,6 +305,49 @@ public class ObjectStreamField implements Comparable return toset; } + /** + * This method searches for its field reference in the specified class + * object. It requests privileges. If an error occurs the internal field + * reference is not modified. + * + * @throws NoSuchFieldException if the field name does not exist in this class. + * @throws SecurityException if there was an error requesting the privileges. + */ + void lookupField(Class clazz) throws NoSuchFieldException, SecurityException + { + final Field f = clazz.getDeclaredField(name); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + f.setAccessible(true); + return null; + } + }); + + this.field = f; + } + + /** + * This method check whether the field described by this + * instance of ObjectStreamField is compatible with the + * actual implementation of this field. + * + * @throws NullPointerException if this field does not exist + * in the real class. + * @throws InvalidClassException if the types are incompatible. + */ + void checkFieldType() throws InvalidClassException + { + Class ftype = field.getType(); + + if (!ftype.isAssignableFrom(type)) + throw new InvalidClassException + ("invalid field type for " + name + + " in class " + field.getDeclaringClass()); + } + public String toString () { return "ObjectStreamField< " + type + " " + name + " >"; @@ -310,102 +355,102 @@ public class ObjectStreamField implements Comparable final void setBooleanField(Object obj, boolean val) { - try + try { - field.setBoolean(obj, val); + field.setBoolean(obj, val); } - catch(IllegalAccessException x) + catch(IllegalAccessException x) { - throw new InternalError(x.getMessage()); + throw new InternalError(x.getMessage()); } } - + final void setByteField(Object obj, byte val) { - try + try { - field.setByte(obj, val); + field.setByte(obj, val); } - catch(IllegalAccessException x) + catch(IllegalAccessException x) { - throw new InternalError(x.getMessage()); + throw new InternalError(x.getMessage()); } } - + final void setCharField(Object obj, char val) { - try + try { - field.setChar(obj, val); + field.setChar(obj, val); } - catch(IllegalAccessException x) + catch(IllegalAccessException x) { - throw new InternalError(x.getMessage()); + throw new InternalError(x.getMessage()); } } - + final void setShortField(Object obj, short val) { - try + try { - field.setShort(obj, val); + field.setShort(obj, val); } - catch(IllegalAccessException x) + catch(IllegalAccessException x) { - throw new InternalError(x.getMessage()); + throw new InternalError(x.getMessage()); } } - + final void setIntField(Object obj, int val) { - try + try { - field.setInt(obj, val); + field.setInt(obj, val); } - catch(IllegalAccessException x) + catch(IllegalAccessException x) { - throw new InternalError(x.getMessage()); + throw new InternalError(x.getMessage()); } } - + final void setLongField(Object obj, long val) { - try + try { - field.setLong(obj, val); + field.setLong(obj, val); } - catch(IllegalAccessException x) + catch(IllegalAccessException x) { - throw new InternalError(x.getMessage()); + throw new InternalError(x.getMessage()); } } - + final void setFloatField(Object obj, float val) { - try + try { - field.setFloat(obj, val); + field.setFloat(obj, val); } - catch(IllegalAccessException x) + catch(IllegalAccessException x) { - throw new InternalError(x.getMessage()); + throw new InternalError(x.getMessage()); } } - + final void setDoubleField(Object obj, double val) { - try + try { - field.setDouble(obj, val); + field.setDouble(obj, val); } - catch(IllegalAccessException x) + catch(IllegalAccessException x) { - throw new InternalError(x.getMessage()); + throw new InternalError(x.getMessage()); } } - + final void setObjectField(Object obj, Object val) - { + { try { field.set(obj, val);