src/java.base/share/classes/java/io/ObjectInputStream.java

Print this page

        

*** 250,262 **** /** scratch field for passing handle values up/down call stack */ private int passHandle = NULL_HANDLE; /** flag set when at end of field value block with no TC_ENDBLOCKDATA */ private boolean defaultDataEnd = false; - /** buffer for reading primitive field values */ - private byte[] primVals; - /** if true, invoke readObjectOverride() instead of readObject() */ private final boolean enableOverride; /** if true, invoke resolveObject() */ private boolean enableResolve; --- 250,259 ----
*** 495,505 **** throw new NotActiveException("not in call to readObject"); } Object curObj = ctx.getObj(); ObjectStreamClass curDesc = ctx.getDesc(); bin.setBlockDataMode(false); ! defaultReadFields(curObj, curDesc); bin.setBlockDataMode(true); if (!curDesc.hasWriteObjectData()) { /* * Fix for 4360508: since stream does not contain terminating * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere --- 492,506 ---- throw new NotActiveException("not in call to readObject"); } Object curObj = ctx.getObj(); ObjectStreamClass curDesc = ctx.getDesc(); bin.setBlockDataMode(false); ! FieldValues vals = defaultReadFields(curObj, curDesc); ! if (curObj != null) { ! defaultCheckFieldValues(curObj, curDesc, vals); ! defaultSetFieldValues(curObj, curDesc, vals); ! } bin.setBlockDataMode(true); if (!curDesc.hasWriteObjectData()) { /* * Fix for 4360508: since stream does not contain terminating * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
*** 1876,1885 **** --- 1877,1906 ---- */ private void readSerialData(Object obj, ObjectStreamClass desc) throws IOException { ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout(); + // Best effort Failure Atomicity; slotValues will be non-null if field + // values can be set after reading all field data in the hierarchy. + // Field values can only be set after reading all data if there are no + // user observable methods in the hierarchy, readObject(NoData). The + // top most Serializable class in the hierarchy can be skipped. + FieldValues[] slotValues = null; + + boolean hasSpecialReadMethod = false; + for (int i = 1; i < slots.length; i++) { + ObjectStreamClass slotDesc = slots[i].desc; + if (slotDesc.hasReadObjectMethod() + || slotDesc.hasReadObjectNoDataMethod()) { + hasSpecialReadMethod = true; + break; + } + } + // No special read methods, can store values and defer setting. + if (!hasSpecialReadMethod) + slotValues = new FieldValues[slots.length]; + for (int i = 0; i < slots.length; i++) { ObjectStreamClass slotDesc = slots[i].desc; if (slots[i].hasData) { if (obj != null &&
*** 1912,1922 **** * readObject() method when calling defaultReadObject() or * readFields(); clear it to restore normal read behavior. */ defaultDataEnd = false; } else { ! defaultReadFields(obj, slotDesc); } if (slotDesc.hasWriteObjectData()) { skipCustomData(); } else { bin.setBlockDataMode(false); --- 1933,1949 ---- * readObject() method when calling defaultReadObject() or * readFields(); clear it to restore normal read behavior. */ defaultDataEnd = false; } else { ! FieldValues vals = defaultReadFields(obj, slotDesc); ! if (slotValues != null) { ! slotValues[i] = vals; ! } else if (obj != null) { ! defaultCheckFieldValues(obj, slotDesc, vals); ! defaultSetFieldValues(obj, slotDesc, vals); ! } } if (slotDesc.hasWriteObjectData()) { skipCustomData(); } else { bin.setBlockDataMode(false);
*** 1928,1937 **** --- 1955,1977 ---- { slotDesc.invokeReadObjectNoData(obj); } } } + + if (obj != null && slotValues != null) { + // Check that the non-primitive types are assignable for all slots + // before assigning. + for (int i = 0; i < slots.length; i++) { + if (slotValues[i] != null) + defaultCheckFieldValues(obj, slots[i].desc, slotValues[i]); + } + for (int i = 0; i < slots.length; i++) { + if (slotValues[i] != null) + defaultSetFieldValues(obj, slots[i].desc, slotValues[i]); + } + } } /** * Skips over all block data and objects until TC_ENDBLOCKDATA is * encountered.
*** 1959,2010 **** break; } } } /** * Reads in values of serializable fields declared by given class ! * descriptor. If obj is non-null, sets field values in obj. Expects that ! * passHandle is set to obj's handle before this method is called. */ ! private void defaultReadFields(Object obj, ObjectStreamClass desc) throws IOException { Class<?> cl = desc.forClass(); if (cl != null && obj != null && !cl.isInstance(obj)) { throw new ClassCastException(); } int primDataSize = desc.getPrimDataSize(); if (primDataSize > 0) { - if (primVals == null || primVals.length < primDataSize) { primVals = new byte[primDataSize]; - } bin.readFully(primVals, 0, primDataSize, false); - if (obj != null) { - desc.setPrimFieldValues(obj, primVals); - } } int numObjFields = desc.getNumObjFields(); if (numObjFields > 0) { int objHandle = passHandle; ObjectStreamField[] fields = desc.getFields(false); ! Object[] objVals = new Object[numObjFields]; int numPrimFields = fields.length - objVals.length; for (int i = 0; i < objVals.length; i++) { ObjectStreamField f = fields[numPrimFields + i]; objVals[i] = readObject0(f.isUnshared()); if (f.getField() != null) { handles.markDependency(objHandle, passHandle); } } - if (obj != null) { - desc.setObjFieldValues(obj, objVals); - } passHandle = objHandle; } } /** * Reads in and returns IOException that caused serialization to abort. * All stream state is discarded prior to reading in fatal exception. Sets --- 1999,2076 ---- break; } } } + private class FieldValues { + final byte[] primValues; + final Object[] objValues; + + FieldValues(byte[] primValues, Object[] objValues) { + this.primValues = primValues; + this.objValues = objValues; + } + } + /** * Reads in values of serializable fields declared by given class ! * descriptor. Expects that passHandle is set to obj's handle before this ! * method is called. */ ! private FieldValues defaultReadFields(Object obj, ObjectStreamClass desc) throws IOException { Class<?> cl = desc.forClass(); if (cl != null && obj != null && !cl.isInstance(obj)) { throw new ClassCastException(); } + byte[] primVals = null; int primDataSize = desc.getPrimDataSize(); if (primDataSize > 0) { primVals = new byte[primDataSize]; bin.readFully(primVals, 0, primDataSize, false); } + Object[] objVals = null; int numObjFields = desc.getNumObjFields(); if (numObjFields > 0) { int objHandle = passHandle; ObjectStreamField[] fields = desc.getFields(false); ! objVals = new Object[numObjFields]; int numPrimFields = fields.length - objVals.length; for (int i = 0; i < objVals.length; i++) { ObjectStreamField f = fields[numPrimFields + i]; objVals[i] = readObject0(f.isUnshared()); if (f.getField() != null) { handles.markDependency(objHandle, passHandle); } } passHandle = objHandle; } + + return new FieldValues(primVals, objVals); + } + + /** Throws ClassCastException if any value is not assignable. */ + private void defaultCheckFieldValues(Object obj, ObjectStreamClass desc, + FieldValues values) { + Object[] objectValues = values.objValues; + if (objectValues != null) + desc.checkObjFieldValueTypes(obj, objectValues); + } + + /** Sets field values in obj. */ + private void defaultSetFieldValues(Object obj, ObjectStreamClass desc, + FieldValues values) { + byte[] primValues = values.primValues; + Object[] objectValues = values.objValues; + + if (primValues != null) + desc.setPrimFieldValues(obj, primValues); + if (objectValues != null) + desc.setObjFieldValues(obj, objectValues); } /** * Reads in and returns IOException that caused serialization to abort. * All stream state is discarded prior to reading in fatal exception. Sets