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.

From-SVN: r78627
This commit is contained in:
Guilhem Lavaux 2004-02-28 21:28:53 +00:00 committed by Michael Koch
parent ca67f27850
commit 646e329010
4 changed files with 317 additions and 173 deletions

View file

@ -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)
{

View file

@ -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;
}

View file

@ -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);