9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.io;
27
28 import java.io.ObjectInputFilter.Config;
29 import java.io.ObjectStreamClass.RecordSupport;
30 import java.lang.System.Logger;
31 import java.lang.invoke.MethodHandle;
32 import java.lang.reflect.Array;
33 import java.lang.reflect.InvocationHandler;
34 import java.lang.reflect.Modifier;
35 import java.lang.reflect.Proxy;
36 import java.nio.charset.StandardCharsets;
37 import java.security.AccessControlContext;
38 import java.security.AccessController;
39 import java.security.PrivilegedAction;
40 import java.security.PrivilegedActionException;
41 import java.security.PrivilegedExceptionAction;
42 import java.util.Arrays;
43 import java.util.Map;
44 import java.util.Objects;
45
46 import jdk.internal.access.JavaLangAccess;
47 import jdk.internal.access.SharedSecrets;
48 import jdk.internal.event.DeserializationEvent;
49 import jdk.internal.misc.Unsafe;
50 import jdk.internal.util.ByteArray;
51 import sun.reflect.misc.ReflectUtil;
52 import sun.security.action.GetBooleanAction;
53 import sun.security.action.GetIntegerAction;
54
55 /**
56 * An ObjectInputStream deserializes primitive data and objects previously
57 * written using an ObjectOutputStream.
58 *
59 * <p><strong>Warning: Deserialization of untrusted data is inherently dangerous
60 * and should be avoided. Untrusted data should be carefully validated according to the
61 * "Serialization and Deserialization" section of the
62 * {@extLink secure_coding_guidelines_javase Secure Coding Guidelines for Java SE}.
63 * {@extLink serialization_filter_guide Serialization Filtering} describes best
64 * practices for defensive use of serial filters.
65 * </strong></p>
66 *
67 * <p>The key to disabling deserialization attacks is to prevent instances of
68 * arbitrary classes from being deserialized, thereby preventing the direct or
69 * indirect execution of their methods.
70 * {@link ObjectInputFilter} describes how to use filters and
71 * {@link ObjectInputFilter.Config} describes how to configure the filter and filter factory.
72 * Each stream has an optional deserialization filter
73 * to check the classes and resource limits during deserialization.
202 * <p>Serialization does not read or assign values to the fields of any object
203 * that does not implement the java.io.Serializable interface. Subclasses of
204 * Objects that are not serializable can be serializable. In this case the
205 * non-serializable class must have a no-arg constructor to allow its fields to
206 * be initialized. In this case it is the responsibility of the subclass to
207 * save and restore the state of the non-serializable class. It is frequently
208 * the case that the fields of that class are accessible (public, package, or
209 * protected) or that there are get and set methods that can be used to restore
210 * the state.
211 *
212 * <p>Any exception that occurs while deserializing an object will be caught by
213 * the ObjectInputStream and abort the reading process.
214 *
215 * <p>Implementing the Externalizable interface allows the object to assume
216 * complete control over the contents and format of the object's serialized
217 * form. The methods of the Externalizable interface, writeExternal and
218 * readExternal, are called to save and restore the objects state. When
219 * implemented by a class they can write and read their own state using all of
220 * the methods of ObjectOutput and ObjectInput. It is the responsibility of
221 * the objects to handle any versioning that occurs.
222 *
223 * <p>Enum constants are deserialized differently than ordinary serializable or
224 * externalizable objects. The serialized form of an enum constant consists
225 * solely of its name; field values of the constant are not transmitted. To
226 * deserialize an enum constant, ObjectInputStream reads the constant name from
227 * the stream; the deserialized constant is then obtained by calling the static
228 * method {@code Enum.valueOf(Class, String)} with the enum constant's
229 * base type and the received constant name as arguments. Like other
230 * serializable or externalizable objects, enum constants can function as the
231 * targets of back references appearing subsequently in the serialization
232 * stream. The process by which enum constants are deserialized cannot be
233 * customized: any class-specific readObject, readObjectNoData, and readResolve
234 * methods defined by enum types are ignored during deserialization.
235 * Similarly, any serialPersistentFields or serialVersionUID field declarations
236 * are also ignored--all enum types have a fixed serialVersionUID of 0L.
237 *
238 * <a id="record-serialization"></a>
239 * <p>Records are serialized differently than ordinary serializable or externalizable
240 * objects. During deserialization the record's canonical constructor is invoked
241 * to construct the record object. Certain serialization-related methods, such
242 * as readObject and writeObject, are ignored for serializable records. See
243 * <a href="{@docRoot}/../specs/serialization/serial-arch.html#serialization-of-records">
244 * <cite>Java Object Serialization Specification,</cite> Section 1.13,
245 * "Serialization of Records"</a> for additional information.
246 *
247 * @spec serialization/index.html Java Object Serialization Specification
248 * @author Mike Warres
249 * @author Roger Riggs
250 * @see java.io.DataInput
251 * @see java.io.ObjectOutputStream
252 * @see java.io.Serializable
253 * @see <a href="{@docRoot}/../specs/serialization/input.html">
254 * <cite>Java Object Serialization Specification,</cite> Section 3, "Object Input Classes"</a>
255 * @since 1.1
256 */
257 public class ObjectInputStream
258 extends InputStream implements ObjectInput, ObjectStreamConstants
259 {
260 /** handle value representing null */
261 private static final int NULL_HANDLE = -1;
262
263 /** marker for unshared objects in internal handle table */
264 private static final Object unsharedMarker = new Object();
265
266 private static class Caches {
267 /** cache of subclass security audit results */
268 static final ClassValue<Boolean> subclassAudits =
269 new ClassValue<>() {
270 @Override
271 protected Boolean computeValue(Class<?> type) {
272 return auditSubclass(type);
273 }
274 };
275
276 /**
277 * Property to permit setting a filter after objects
278 * have been read.
279 * See {@link #setObjectInputFilter(ObjectInputFilter)}
449
450 /**
451 * Read an object from the ObjectInputStream. The class of the object, the
452 * signature of the class, and the values of the non-transient and
453 * non-static fields of the class and all of its supertypes are read.
454 * Default deserializing for a class can be overridden using the writeObject
455 * and readObject methods. Objects referenced by this object are read
456 * transitively so that a complete equivalent graph of objects is
457 * reconstructed by readObject.
458 *
459 * <p>The root object is completely restored when all of its fields and the
460 * objects it references are completely restored. At this point the object
461 * validation callbacks are executed in order based on their registered
462 * priorities. The callbacks are registered by objects (in the readObject
463 * special methods) as they are individually restored.
464 *
465 * <p>The deserialization filter, when not {@code null}, is invoked for
466 * each object (regular or class) read to reconstruct the root object.
467 * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
468 *
469 * <p>Exceptions are thrown for problems with the InputStream and for
470 * classes that should not be deserialized. All exceptions are fatal to
471 * the InputStream and leave it in an indeterminate state; it is up to the
472 * caller to ignore or recover the stream state.
473 *
474 * @throws ClassNotFoundException Class of a serialized object cannot be
475 * found.
476 * @throws InvalidClassException Something is wrong with a class used by
477 * deserialization.
478 * @throws StreamCorruptedException Control information in the
479 * stream is inconsistent.
480 * @throws OptionalDataException Primitive data was found in the
481 * stream instead of objects.
482 * @throws IOException Any of the usual Input/Output related exceptions.
483 */
484 public final Object readObject()
485 throws IOException, ClassNotFoundException {
486 return readObject(Object.class);
487 }
488
582 * to deserialize back-references to the stream handle deserialized
583 * by readUnshared will cause an ObjectStreamException to be thrown.
584 * </ul>
585 * Deserializing an object via readUnshared invalidates the stream handle
586 * associated with the returned object. Note that this in itself does not
587 * always guarantee that the reference returned by readUnshared is unique;
588 * the deserialized object may define a readResolve method which returns an
589 * object visible to other parties, or readUnshared may return a Class
590 * object or enum constant obtainable elsewhere in the stream or through
591 * external means. If the deserialized object defines a readResolve method
592 * and the invocation of that method returns an array, then readUnshared
593 * returns a shallow clone of that array; this guarantees that the returned
594 * array object is unique and cannot be obtained a second time from an
595 * invocation of readObject or readUnshared on the ObjectInputStream,
596 * even if the underlying data stream has been manipulated.
597 *
598 * <p>The deserialization filter, when not {@code null}, is invoked for
599 * each object (regular or class) read to reconstruct the root object.
600 * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
601 *
602 * <p>ObjectInputStream subclasses which override this method can only be
603 * constructed in security contexts possessing the
604 * "enableSubclassImplementation" SerializablePermission; any attempt to
605 * instantiate such a subclass without this permission will cause a
606 * SecurityException to be thrown.
607 *
608 * @return reference to deserialized object
609 * @throws ClassNotFoundException if class of an object to deserialize
610 * cannot be found
611 * @throws StreamCorruptedException if control information in the stream
612 * is inconsistent
613 * @throws ObjectStreamException if object to deserialize has already
614 * appeared in stream
615 * @throws OptionalDataException if primitive data is next in stream
616 * @throws IOException if an I/O error occurs during deserialization
617 * @since 1.4
618 */
619 public Object readUnshared() throws IOException, ClassNotFoundException {
620 // if nested read, passHandle contains handle of enclosing object
621 int outerHandle = passHandle;
2235 * class is unresolvable (in which case a ClassNotFoundException will be
2236 * associated with object's handle). Sets passHandle to object's assigned
2237 * handle.
2238 */
2239 private Object readOrdinaryObject(boolean unshared)
2240 throws IOException
2241 {
2242 if (bin.readByte() != TC_OBJECT) {
2243 throw new InternalError();
2244 }
2245
2246 ObjectStreamClass desc = readClassDesc(false);
2247 desc.checkDeserialize();
2248
2249 Class<?> cl = desc.forClass();
2250 if (cl == String.class || cl == Class.class
2251 || cl == ObjectStreamClass.class) {
2252 throw new InvalidClassException("invalid class descriptor");
2253 }
2254
2255 Object obj;
2256 try {
2257 obj = desc.isInstantiable() ? desc.newInstance() : null;
2258 } catch (Exception ex) {
2259 throw new InvalidClassException(desc.forClass().getName(),
2260 "unable to create instance", ex);
2261 }
2262
2263 passHandle = handles.assign(unshared ? unsharedMarker : obj);
2264 ClassNotFoundException resolveEx = desc.getResolveException();
2265 if (resolveEx != null) {
2266 handles.markException(passHandle, resolveEx);
2267 }
2268
2269 final boolean isRecord = desc.isRecord();
2270 if (isRecord) {
2271 assert obj == null;
2272 obj = readRecord(desc);
2273 if (!unshared)
2274 handles.setObject(passHandle, obj);
2275 } else if (desc.isExternalizable()) {
2276 readExternalData((Externalizable) obj, desc);
2277 } else {
2278 readSerialData(obj, desc);
2279 }
2280
2281 handles.finish(passHandle);
2282
2283 if (obj != null &&
2284 handles.lookupException(passHandle) == null &&
2285 desc.hasReadResolveMethod())
2286 {
2287 Object rep = desc.invokeReadResolve(obj);
2288 if (unshared && rep.getClass().isArray()) {
2289 rep = cloneArray(rep);
2290 }
2291 if (rep != obj) {
2292 // Filter the replacement object
2293 if (rep != null) {
2294 if (rep.getClass().isArray()) {
2295 filterCheck(rep.getClass(), Array.getLength(rep));
2296 } else {
2297 filterCheck(rep.getClass(), -1);
2298 }
2299 }
2300 handles.setObject(passHandle, obj = rep);
2301 }
2302 }
2303
2304 return obj;
2305 }
2306
2307 /**
2308 * If obj is non-null, reads externalizable data by invoking readExternal()
2309 * method of obj; otherwise, attempts to skip over externalizable data.
2310 * Expects that passHandle is set to obj's handle before this method is
2311 * called.
2312 */
2313 private void readExternalData(Externalizable obj, ObjectStreamClass desc)
2314 throws IOException
2315 {
2316 SerialCallbackContext oldContext = curContext;
2317 if (oldContext != null)
2318 oldContext.check();
2319 curContext = null;
2320 try {
2321 boolean blocked = desc.hasBlockExternalData();
2322 if (blocked) {
2323 bin.setBlockDataMode(true);
2324 }
2325 if (obj != null) {
2326 try {
2327 obj.readExternal(this);
2328 } catch (ClassNotFoundException ex) {
2329 /*
2330 * In most cases, the handle table has already propagated
2331 * a CNFException to passHandle at this point; this mark
2332 * call is included to address cases where the readExternal
2333 * method has cons'ed and thrown a new CNFException of its
2334 * own.
2335 */
2339 if (blocked) {
2340 skipCustomData();
2341 }
2342 } finally {
2343 if (oldContext != null)
2344 oldContext.check();
2345 curContext = oldContext;
2346 }
2347 /*
2348 * At this point, if the externalizable data was not written in
2349 * block-data form and either the externalizable class doesn't exist
2350 * locally (i.e., obj == null) or readExternal() just threw a
2351 * CNFException, then the stream is probably in an inconsistent state,
2352 * since some (or all) of the externalizable data may not have been
2353 * consumed. Since there's no "correct" action to take in this case,
2354 * we mimic the behavior of past serialization implementations and
2355 * blindly hope that the stream is in sync; if it isn't and additional
2356 * externalizable data remains in the stream, a subsequent read will
2357 * most likely throw a StreamCorruptedException.
2358 */
2359 }
2360
2361 /**
2362 * Reads and returns a record.
2363 * If an exception is marked for any of the fields, the dependency
2364 * mechanism marks the record as having an exception.
2365 * Null is returned from readRecord and later the exception is thrown at
2366 * the exit of {@link #readObject(Class)}.
2367 **/
2368 private Object readRecord(ObjectStreamClass desc) throws IOException {
2369 ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
2370 if (slots.length != 1) {
2371 // skip any superclass stream field values
2372 for (int i = 0; i < slots.length-1; i++) {
2373 if (slots[i].hasData) {
2374 new FieldValues(slots[i].desc, true);
2375 }
2376 }
2377 }
2378
2379 FieldValues fieldValues = new FieldValues(desc, true);
2380 if (handles.lookupException(passHandle) != null) {
2381 return null; // slot marked with exception, don't create record
2382 }
2383
2384 // get canonical record constructor adapted to take two arguments:
2385 // - byte[] primValues
2386 // - Object[] objValues
2387 // and return Object
2388 MethodHandle ctrMH = RecordSupport.deserializationCtr(desc);
2389
2390 try {
2391 return (Object) ctrMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
2392 } catch (Exception e) {
2393 throw new InvalidObjectException(e.getMessage(), e);
2394 } catch (Error e) {
2395 throw e;
2396 } catch (Throwable t) {
2397 throw new InvalidObjectException("ReflectiveOperationException " +
2398 "during deserialization", t);
2399 }
2400 }
2401
2402 /**
2403 * Reads (or attempts to skip, if obj is null or is tagged with a
2404 * ClassNotFoundException) instance data for each serializable class of
2405 * object in stream, from superclass to subclass. Expects that passHandle
2406 * is set to obj's handle before this method is called.
2407 */
2408 private void readSerialData(Object obj, ObjectStreamClass desc)
2409 throws IOException
2410 {
2411 ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
2412 // Best effort Failure Atomicity; slotValues will be non-null if field
2413 // values can be set after reading all field data in the hierarchy.
2414 // Field values can only be set after reading all data if there are no
2415 // user observable methods in the hierarchy, readObject(NoData). The
2416 // top most Serializable class in the hierarchy can be skipped.
2417 FieldValues[] slotValues = null;
2418
2419 boolean hasSpecialReadMethod = false;
2420 for (int i = 1; i < slots.length; i++) {
2421 ObjectStreamClass slotDesc = slots[i].desc;
2422 if (slotDesc.hasReadObjectMethod()
2423 || slotDesc.hasReadObjectNoDataMethod()) {
2424 hasSpecialReadMethod = true;
2425 break;
2426 }
2427 }
2428 // No special read methods, can store values and defer setting.
2429 if (!hasSpecialReadMethod)
2430 slotValues = new FieldValues[slots.length];
2431
2432 for (int i = 0; i < slots.length; i++) {
2433 ObjectStreamClass slotDesc = slots[i].desc;
2434
2435 if (slots[i].hasData) {
2436 if (obj == null || handles.lookupException(passHandle) != null) {
2437 // Read fields of the current descriptor into a new FieldValues and discard
2438 new FieldValues(slotDesc, true);
2439 } else if (slotDesc.hasReadObjectMethod()) {
2440 SerialCallbackContext oldContext = curContext;
2441 if (oldContext != null)
2442 oldContext.check();
2443 try {
2444 curContext = new SerialCallbackContext(obj, slotDesc);
2445
2446 bin.setBlockDataMode(true);
2447 slotDesc.invokeReadObject(obj, this);
2448 } catch (ClassNotFoundException ex) {
2449 /*
2450 * In most cases, the handle table has already
2451 * propagated a CNFException to passHandle at this
2452 * point; this mark call is included to address cases
2453 * where the custom readObject method has cons'ed and
2454 * thrown a new CNFException of its own.
2455 */
2456 handles.markException(passHandle, ex);
2457 } finally {
2458 curContext.setUsed();
2459 if (oldContext!= null)
2460 oldContext.check();
2461 curContext = oldContext;
2462 }
2463
2464 /*
2465 * defaultDataEnd may have been set indirectly by custom
2466 * readObject() method when calling defaultReadObject() or
2467 * readFields(); clear it to restore normal read behavior.
2468 */
2469 defaultDataEnd = false;
2470 } else {
2471 // Read fields of the current descriptor into a new FieldValues
2472 FieldValues values = new FieldValues(slotDesc, true);
2473 if (slotValues != null) {
2474 slotValues[i] = values;
2475 } else if (obj != null) {
2476 if (handles.lookupException(passHandle) == null) {
2477 // passHandle NOT marked with an exception; set field values
2478 values.defaultCheckFieldValues(obj);
2479 values.defaultSetFieldValues(obj);
2480 }
2481 }
2482 }
2483
2484 if (slotDesc.hasWriteObjectData()) {
2485 skipCustomData();
2486 } else {
2487 bin.setBlockDataMode(false);
2488 }
2489 } else {
2490 if (obj != null &&
2491 slotDesc.hasReadObjectNoDataMethod() &&
2492 handles.lookupException(passHandle) == null)
2493 {
2494 slotDesc.invokeReadObjectNoData(obj);
2495 }
2496 }
2497 }
2498
2499 if (obj != null && slotValues != null && handles.lookupException(passHandle) == null) {
2500 // passHandle NOT marked with an exception
2501 // Check that the non-primitive types are assignable for all slots
2502 // before assigning.
2503 for (int i = 0; i < slots.length; i++) {
2504 if (slotValues[i] != null)
2505 slotValues[i].defaultCheckFieldValues(obj);
2506 }
2507 for (int i = 0; i < slots.length; i++) {
2508 if (slotValues[i] != null)
2509 slotValues[i].defaultSetFieldValues(obj);
2510 }
2511 }
2512 }
2513
2514 /**
2515 * Skips over all block data and objects until TC_ENDBLOCKDATA is
2516 * encountered.
2517 */
2518 private void skipCustomData() throws IOException {
2519 int oldHandle = passHandle;
2520 for (;;) {
2521 if (bin.getBlockDataMode()) {
2522 bin.skipBlockData();
2523 bin.setBlockDataMode(false);
2524 }
2525 switch (bin.peekByte()) {
2526 case TC_BLOCKDATA:
2527 case TC_BLOCKDATALONG:
2528 bin.setBlockDataMode(true);
2529 break;
2530
2586 /**
2587 * Default GetField implementation.
2588 */
2589 private final class FieldValues extends GetField {
2590
2591 /** class descriptor describing serializable fields */
2592 private final ObjectStreamClass desc;
2593 /** primitive field values */
2594 final byte[] primValues;
2595 /** object field values */
2596 final Object[] objValues;
2597 /** object field value handles */
2598 private final int[] objHandles;
2599
2600 /**
2601 * Creates FieldValues object for reading fields defined in given
2602 * class descriptor.
2603 * @param desc the ObjectStreamClass to read
2604 * @param recordDependencies if true, record the dependencies
2605 * from current PassHandle and the object's read.
2606 */
2607 FieldValues(ObjectStreamClass desc, boolean recordDependencies) throws IOException {
2608 this.desc = desc;
2609
2610 int primDataSize = desc.getPrimDataSize();
2611 primValues = (primDataSize > 0) ? new byte[primDataSize] : null;
2612 if (primDataSize > 0) {
2613 bin.readFully(primValues, 0, primDataSize, false);
2614 }
2615
2616 int numObjFields = desc.getNumObjFields();
2617 objValues = (numObjFields > 0) ? new Object[numObjFields] : null;
2618 objHandles = (numObjFields > 0) ? new int[numObjFields] : null;
2619 if (numObjFields > 0) {
2620 int objHandle = passHandle;
2621 ObjectStreamField[] fields = desc.getFields(false);
2622 int numPrimFields = fields.length - objValues.length;
2623 for (int i = 0; i < objValues.length; i++) {
2624 ObjectStreamField f = fields[numPrimFields + i];
2625 objValues[i] = readObject0(Object.class, f.isUnshared());
2626 objHandles[i] = passHandle;
2627 if (recordDependencies && f.getField() != null) {
2628 handles.markDependency(objHandle, passHandle);
2629 }
2630 }
2631 passHandle = objHandle;
2632 }
2633 }
2634
2635 public ObjectStreamClass getObjectStreamClass() {
2636 return desc;
2637 }
2638
2639 public boolean defaulted(String name) {
2640 return (getFieldOffset(name, null) < 0);
2641 }
2642
2643 public boolean get(String name, boolean val) {
2644 int off = getFieldOffset(name, Boolean.TYPE);
2645 return (off >= 0) ? ByteArray.getBoolean(primValues, off) : val;
2646 }
2647
2648 public byte get(String name, byte val) {
2649 int off = getFieldOffset(name, Byte.TYPE);
2650 return (off >= 0) ? primValues[off] : val;
2651 }
|
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.io;
27
28 import java.io.ObjectInputFilter.Config;
29 import java.io.ObjectStreamClass.ConstructorSupport;
30 import java.io.ObjectStreamClass.ClassDataSlot;
31 import java.lang.System.Logger;
32 import java.lang.invoke.MethodHandle;
33 import java.lang.reflect.Array;
34 import java.lang.reflect.InvocationHandler;
35 import java.lang.reflect.InvocationTargetException;
36 import java.lang.reflect.Modifier;
37 import java.lang.reflect.Proxy;
38 import java.nio.charset.StandardCharsets;
39 import java.security.AccessControlContext;
40 import java.security.AccessController;
41 import java.security.PrivilegedAction;
42 import java.security.PrivilegedActionException;
43 import java.security.PrivilegedExceptionAction;
44 import java.util.Arrays;
45 import java.util.List;
46 import java.util.Locale;
47 import java.util.Objects;
48
49 import jdk.internal.access.JavaLangAccess;
50 import jdk.internal.access.SharedSecrets;
51 import jdk.internal.event.DeserializationEvent;
52 import jdk.internal.misc.Unsafe;
53 import jdk.internal.util.ByteArray;
54 import sun.reflect.misc.ReflectUtil;
55 import sun.security.action.GetBooleanAction;
56 import sun.security.action.GetIntegerAction;
57 import sun.security.action.GetPropertyAction;
58
59 /**
60 * An ObjectInputStream deserializes primitive data and objects previously
61 * written using an ObjectOutputStream.
62 *
63 * <p><strong>Warning: Deserialization of untrusted data is inherently dangerous
64 * and should be avoided. Untrusted data should be carefully validated according to the
65 * "Serialization and Deserialization" section of the
66 * {@extLink secure_coding_guidelines_javase Secure Coding Guidelines for Java SE}.
67 * {@extLink serialization_filter_guide Serialization Filtering} describes best
68 * practices for defensive use of serial filters.
69 * </strong></p>
70 *
71 * <p>The key to disabling deserialization attacks is to prevent instances of
72 * arbitrary classes from being deserialized, thereby preventing the direct or
73 * indirect execution of their methods.
74 * {@link ObjectInputFilter} describes how to use filters and
75 * {@link ObjectInputFilter.Config} describes how to configure the filter and filter factory.
76 * Each stream has an optional deserialization filter
77 * to check the classes and resource limits during deserialization.
206 * <p>Serialization does not read or assign values to the fields of any object
207 * that does not implement the java.io.Serializable interface. Subclasses of
208 * Objects that are not serializable can be serializable. In this case the
209 * non-serializable class must have a no-arg constructor to allow its fields to
210 * be initialized. In this case it is the responsibility of the subclass to
211 * save and restore the state of the non-serializable class. It is frequently
212 * the case that the fields of that class are accessible (public, package, or
213 * protected) or that there are get and set methods that can be used to restore
214 * the state.
215 *
216 * <p>Any exception that occurs while deserializing an object will be caught by
217 * the ObjectInputStream and abort the reading process.
218 *
219 * <p>Implementing the Externalizable interface allows the object to assume
220 * complete control over the contents and format of the object's serialized
221 * form. The methods of the Externalizable interface, writeExternal and
222 * readExternal, are called to save and restore the objects state. When
223 * implemented by a class they can write and read their own state using all of
224 * the methods of ObjectOutput and ObjectInput. It is the responsibility of
225 * the objects to handle any versioning that occurs.
226 * Value objects cannot be `java.io.Externalizable` because value objects are
227 * immutable and `Externalizable.readExternal` is unable to modify the fields of the value.
228 *
229 * <p>Enum constants are deserialized differently than ordinary serializable or
230 * externalizable objects. The serialized form of an enum constant consists
231 * solely of its name; field values of the constant are not transmitted. To
232 * deserialize an enum constant, ObjectInputStream reads the constant name from
233 * the stream; the deserialized constant is then obtained by calling the static
234 * method {@code Enum.valueOf(Class, String)} with the enum constant's
235 * base type and the received constant name as arguments. Like other
236 * serializable or externalizable objects, enum constants can function as the
237 * targets of back references appearing subsequently in the serialization
238 * stream. The process by which enum constants are deserialized cannot be
239 * customized: any class-specific readObject, readObjectNoData, and readResolve
240 * methods defined by enum types are ignored during deserialization.
241 * Similarly, any serialPersistentFields or serialVersionUID field declarations
242 * are also ignored--all enum types have a fixed serialVersionUID of 0L.
243 *
244 * <a id="record-serialization"></a>
245 * <p>Records are serialized differently than ordinary serializable or externalizable
246 * objects. During deserialization the record's canonical constructor is invoked
247 * to construct the record object. Certain serialization-related methods, such
248 * as readObject and writeObject, are ignored for serializable records. See
249 * <a href="{@docRoot}/../specs/serialization/serial-arch.html#serialization-of-records">
250 * <cite>Java Object Serialization Specification,</cite> Section 1.13,
251 * "Serialization of Records"</a> for additional information.
252 *
253 * <p>Value classes are {@linkplain Serializable} through the use of the serialization proxy pattern.
254 * See {@linkplain ObjectOutputStream##valueclass-serialization value class serialization} for details.
255 * When the proxy is deserialized it re-constructs and returns the value object.
256 *
257 * @spec serialization/index.html Java Object Serialization Specification
258 * @author Mike Warres
259 * @author Roger Riggs
260 * @see java.io.DataInput
261 * @see java.io.ObjectOutputStream
262 * @see java.io.Serializable
263 * @see <a href="{@docRoot}/../specs/serialization/input.html">
264 * <cite>Java Object Serialization Specification,</cite> Section 3, "Object Input Classes"</a>
265 * @since 1.1
266 */
267 public class ObjectInputStream
268 extends InputStream implements ObjectInput, ObjectStreamConstants
269 {
270 private static final String TRACE_DEST =
271 GetPropertyAction.privilegedGetProperty("TRACE");
272
273 static void TRACE(String format, Object... args) {
274 if (TRACE_DEST != null) {
275 var ps = "OUT".equals(TRACE_DEST.toUpperCase(Locale.ROOT)) ? System.out : System.err;
276 ps.println(("TRACE " + format).formatted(args));
277 }
278 }
279
280 /** handle value representing null */
281 private static final int NULL_HANDLE = -1;
282
283 /** marker for unshared objects in internal handle table */
284 private static final Object unsharedMarker = new Object();
285
286 private static class Caches {
287 /** cache of subclass security audit results */
288 static final ClassValue<Boolean> subclassAudits =
289 new ClassValue<>() {
290 @Override
291 protected Boolean computeValue(Class<?> type) {
292 return auditSubclass(type);
293 }
294 };
295
296 /**
297 * Property to permit setting a filter after objects
298 * have been read.
299 * See {@link #setObjectInputFilter(ObjectInputFilter)}
469
470 /**
471 * Read an object from the ObjectInputStream. The class of the object, the
472 * signature of the class, and the values of the non-transient and
473 * non-static fields of the class and all of its supertypes are read.
474 * Default deserializing for a class can be overridden using the writeObject
475 * and readObject methods. Objects referenced by this object are read
476 * transitively so that a complete equivalent graph of objects is
477 * reconstructed by readObject.
478 *
479 * <p>The root object is completely restored when all of its fields and the
480 * objects it references are completely restored. At this point the object
481 * validation callbacks are executed in order based on their registered
482 * priorities. The callbacks are registered by objects (in the readObject
483 * special methods) as they are individually restored.
484 *
485 * <p>The deserialization filter, when not {@code null}, is invoked for
486 * each object (regular or class) read to reconstruct the root object.
487 * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
488 *
489 * <p>Serialization and deserialization of value classes is described in
490 * {@linkplain ObjectOutputStream##valueclass-serialization value class serialization}.
491 *
492 * @implSpec
493 * When enabled with {@code --enable-preview}, serialization and deserialization of
494 * Core Library value classes migrated from pre-JEP 401 identity classes is
495 * implementation specific.
496 *
497 * <p>Exceptions are thrown for problems with the InputStream and for
498 * classes that should not be deserialized. All exceptions are fatal to
499 * the InputStream and leave it in an indeterminate state; it is up to the
500 * caller to ignore or recover the stream state.
501 *
502 * @throws ClassNotFoundException Class of a serialized object cannot be
503 * found.
504 * @throws InvalidClassException Something is wrong with a class used by
505 * deserialization.
506 * @throws StreamCorruptedException Control information in the
507 * stream is inconsistent.
508 * @throws OptionalDataException Primitive data was found in the
509 * stream instead of objects.
510 * @throws IOException Any of the usual Input/Output related exceptions.
511 */
512 public final Object readObject()
513 throws IOException, ClassNotFoundException {
514 return readObject(Object.class);
515 }
516
610 * to deserialize back-references to the stream handle deserialized
611 * by readUnshared will cause an ObjectStreamException to be thrown.
612 * </ul>
613 * Deserializing an object via readUnshared invalidates the stream handle
614 * associated with the returned object. Note that this in itself does not
615 * always guarantee that the reference returned by readUnshared is unique;
616 * the deserialized object may define a readResolve method which returns an
617 * object visible to other parties, or readUnshared may return a Class
618 * object or enum constant obtainable elsewhere in the stream or through
619 * external means. If the deserialized object defines a readResolve method
620 * and the invocation of that method returns an array, then readUnshared
621 * returns a shallow clone of that array; this guarantees that the returned
622 * array object is unique and cannot be obtained a second time from an
623 * invocation of readObject or readUnshared on the ObjectInputStream,
624 * even if the underlying data stream has been manipulated.
625 *
626 * <p>The deserialization filter, when not {@code null}, is invoked for
627 * each object (regular or class) read to reconstruct the root object.
628 * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
629 *
630 * <p>Serialization and deserialization of value classes is described in
631 * {@linkplain ObjectOutputStream##valueclass-serialization value class serialization}.
632 *
633 * <p>ObjectInputStream subclasses which override this method can only be
634 * constructed in security contexts possessing the
635 * "enableSubclassImplementation" SerializablePermission; any attempt to
636 * instantiate such a subclass without this permission will cause a
637 * SecurityException to be thrown.
638 *
639 * @return reference to deserialized object
640 * @throws ClassNotFoundException if class of an object to deserialize
641 * cannot be found
642 * @throws StreamCorruptedException if control information in the stream
643 * is inconsistent
644 * @throws ObjectStreamException if object to deserialize has already
645 * appeared in stream
646 * @throws OptionalDataException if primitive data is next in stream
647 * @throws IOException if an I/O error occurs during deserialization
648 * @since 1.4
649 */
650 public Object readUnshared() throws IOException, ClassNotFoundException {
651 // if nested read, passHandle contains handle of enclosing object
652 int outerHandle = passHandle;
2266 * class is unresolvable (in which case a ClassNotFoundException will be
2267 * associated with object's handle). Sets passHandle to object's assigned
2268 * handle.
2269 */
2270 private Object readOrdinaryObject(boolean unshared)
2271 throws IOException
2272 {
2273 if (bin.readByte() != TC_OBJECT) {
2274 throw new InternalError();
2275 }
2276
2277 ObjectStreamClass desc = readClassDesc(false);
2278 desc.checkDeserialize();
2279
2280 Class<?> cl = desc.forClass();
2281 if (cl == String.class || cl == Class.class
2282 || cl == ObjectStreamClass.class) {
2283 throw new InvalidClassException("invalid class descriptor");
2284 }
2285
2286 // Assign the handle and initially set to null or the unsharedMarker
2287 passHandle = handles.assign(unshared ? unsharedMarker : null);
2288 ClassNotFoundException resolveEx = desc.getResolveException();
2289 if (resolveEx != null) {
2290 handles.markException(passHandle, resolveEx);
2291 }
2292
2293 try {
2294 // Dispatch on the factory mode to read an object from the stream.
2295 Object obj = switch (desc.factoryMode()) {
2296 case READ_OBJECT_DEFAULT -> readSerialDefaultObject(desc, unshared);
2297 case READ_OBJECT_CUSTOM -> readSerialCustomData(desc, unshared);
2298 case READ_RECORD -> readRecord(desc, unshared);
2299 case READ_EXTERNALIZABLE -> readExternalObject(desc, unshared);
2300 case READ_OBJECT_VALUE -> readObjectValue(desc, unshared);
2301 case READ_NO_LOCAL_CLASS -> readAbsentLocalClass(desc, unshared);
2302 case null -> throw new AssertionError("Unknown factoryMode for: " + desc.getName(),
2303 resolveEx);
2304 };
2305
2306 handles.finish(passHandle);
2307
2308 if (obj != null &&
2309 handles.lookupException(passHandle) == null &&
2310 desc.hasReadResolveMethod())
2311 {
2312 Object rep = desc.invokeReadResolve(obj);
2313 if (unshared && rep.getClass().isArray()) {
2314 rep = cloneArray(rep);
2315 }
2316 if (rep != obj) {
2317 // Filter the replacement object
2318 if (rep != null) {
2319 if (rep.getClass().isArray()) {
2320 filterCheck(rep.getClass(), Array.getLength(rep));
2321 } else {
2322 filterCheck(rep.getClass(), -1);
2323 }
2324 }
2325 handles.setObject(passHandle, obj = rep);
2326 }
2327 }
2328
2329 return obj;
2330 } catch (UncheckedIOException uioe) {
2331 // Consistent re-throw for nested UncheckedIOExceptions
2332 throw uioe.getCause();
2333 }
2334 }
2335
2336 /**
2337 * {@return a value class instance by invoking its constructor with field values read from the stream.
2338 * The fields of the class in the stream are matched to the local fields and applied to
2339 * the constructor.
2340 * If the stream contains superclasses with serializable fields,
2341 * an InvalidClassException is thrown with an incompatible class change message.
2342 *
2343 * @param desc the class descriptor read from the stream, the local class is a value class
2344 * @param unshared if the object is not to be shared
2345 * @throws InvalidClassException if the stream contains a superclass with serializable fields.
2346 * @throws IOException if there are I/O errors while reading from the
2347 * underlying {@code InputStream}
2348 */
2349 private Object readObjectValue(ObjectStreamClass desc, boolean unshared) throws IOException {
2350 final ObjectStreamClass localDesc = desc.getLocalDesc();
2351 TRACE("readObjectValue: %s, local class: %s", desc.getName(), localDesc.getName());
2352 // Check for un-expected fields in superclasses
2353 List<ClassDataSlot> slots = desc.getClassDataLayout();
2354 for (int i = 0; i < slots.size()-1; i++) {
2355 ClassDataSlot slot = slots.get(i);
2356 if (slot.hasData && slot.desc.getFields(false).length > 0) {
2357 throw new InvalidClassException("incompatible class change to value class: " +
2358 "stream class has non-empty super type: " + desc.getName());
2359 }
2360 }
2361 // Read values for the value class fields
2362 FieldValues fieldValues = new FieldValues(desc, true);
2363
2364 // Get value object constructor adapted to take primitive value buffer and object array.
2365 MethodHandle consMH = ConstructorSupport.deserializationValueCons(desc);
2366 try {
2367 Object obj = (Object) consMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
2368 if (!unshared)
2369 handles.setObject(passHandle, obj);
2370 return obj;
2371 } catch (Exception e) {
2372 throw new InvalidObjectException(e.getMessage(), e);
2373 } catch (Error e) {
2374 throw e;
2375 } catch (Throwable t) {
2376 throw new InvalidObjectException("ReflectiveOperationException " +
2377 "during deserialization", t);
2378 }
2379 }
2380
2381 /**
2382 * Creates a new object and invokes its readExternal method to read its contents.
2383 *
2384 * If the class is instantiable, read externalizable data by invoking readExternal()
2385 * method of obj; otherwise, attempts to skip over externalizable data.
2386 * Expects that passHandle is set to obj's handle before this method is
2387 * called. The new object is entered in the handle table immediately,
2388 * allowing it to leak before it is completely read.
2389 */
2390 private Object readExternalObject(ObjectStreamClass desc, boolean unshared)
2391 throws IOException
2392 {
2393 TRACE("readExternalObject: %s", desc.getName());
2394
2395 // For Externalizable objects,
2396 // create the instance, publish the ref, and read the data
2397 Externalizable obj = null;
2398 try {
2399 if (desc.isInstantiable()) {
2400 obj = (Externalizable) desc.newInstance();
2401 }
2402 } catch (Exception ex) {
2403 throw new InvalidClassException(desc.getName(),
2404 "unable to create instance", ex);
2405 }
2406
2407 if (!unshared)
2408 handles.setObject(passHandle, obj);
2409
2410 SerialCallbackContext oldContext = curContext;
2411 if (oldContext != null)
2412 oldContext.check();
2413 curContext = null;
2414 try {
2415 boolean blocked = desc.hasBlockExternalData();
2416 if (blocked) {
2417 bin.setBlockDataMode(true);
2418 }
2419 if (obj != null) {
2420 try {
2421 obj.readExternal(this);
2422 } catch (ClassNotFoundException ex) {
2423 /*
2424 * In most cases, the handle table has already propagated
2425 * a CNFException to passHandle at this point; this mark
2426 * call is included to address cases where the readExternal
2427 * method has cons'ed and thrown a new CNFException of its
2428 * own.
2429 */
2433 if (blocked) {
2434 skipCustomData();
2435 }
2436 } finally {
2437 if (oldContext != null)
2438 oldContext.check();
2439 curContext = oldContext;
2440 }
2441 /*
2442 * At this point, if the externalizable data was not written in
2443 * block-data form and either the externalizable class doesn't exist
2444 * locally (i.e., obj == null) or readExternal() just threw a
2445 * CNFException, then the stream is probably in an inconsistent state,
2446 * since some (or all) of the externalizable data may not have been
2447 * consumed. Since there's no "correct" action to take in this case,
2448 * we mimic the behavior of past serialization implementations and
2449 * blindly hope that the stream is in sync; if it isn't and additional
2450 * externalizable data remains in the stream, a subsequent read will
2451 * most likely throw a StreamCorruptedException.
2452 */
2453 return obj;
2454 }
2455
2456 /**
2457 * Reads and returns a record.
2458 * If an exception is marked for any of the fields, the dependency
2459 * mechanism marks the record as having an exception.
2460 * Null is returned from readRecord and later the exception is thrown at
2461 * the exit of {@link #readObject(Class)}.
2462 */
2463 private Object readRecord(ObjectStreamClass desc, boolean unshared) throws IOException {
2464 TRACE("invoking readRecord: %s", desc.getName());
2465 List<ClassDataSlot> slots = desc.getClassDataLayout();
2466 if (slots.size() != 1) {
2467 // skip any superclass stream field values
2468 for (int i = 0; i < slots.size()-1; i++) {
2469 if (slots.get(i).hasData) {
2470 new FieldValues(slots.get(i).desc, true);
2471 }
2472 }
2473 }
2474
2475 FieldValues fieldValues = new FieldValues(desc, true);
2476 if (handles.lookupException(passHandle) != null) {
2477 return null; // slot marked with exception, don't create record
2478 }
2479
2480 // get canonical record constructor adapted to take two arguments:
2481 // - byte[] primValues
2482 // - Object[] objValues
2483 // and return Object
2484 MethodHandle ctrMH = ConstructorSupport.deserializationCtr(desc);
2485
2486 try {
2487 Object obj = (Object) ctrMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
2488 if (!unshared)
2489 handles.setObject(passHandle, obj);
2490 return obj;
2491 } catch (Exception e) {
2492 throw new InvalidObjectException(e.getMessage(), e);
2493 } catch (Error e) {
2494 throw e;
2495 } catch (Throwable t) {
2496 throw new InvalidObjectException("ReflectiveOperationException " +
2497 "during deserialization", t);
2498 }
2499 }
2500
2501 /**
2502 * Construct an object from the stream for a class that has only default read object behaviors.
2503 * For each object, the fields are read before any are assigned.
2504 * The new instance is entered in the handle table if it is unshared,
2505 * allowing it to escape before it is initialized.
2506 * The `readObject` and `readObjectNoData` methods are not present and are not called.
2507 *
2508 * @param desc the class descriptor
2509 * @param unshared true if the object should be shared
2510 * @return the object constructed from the stream data
2511 * @throws IOException if there are I/O errors while reading from the
2512 * underlying {@code InputStream}
2513 * @throws InvalidClassException if the instance creation fails
2514 */
2515 private Object readSerialDefaultObject(ObjectStreamClass desc, boolean unshared)
2516 throws IOException, InvalidClassException {
2517 if (!desc.isInstantiable()) {
2518 // No local class to create, read and discard
2519 return readAbsentLocalClass(desc, unshared);
2520 }
2521 TRACE("readSerialDefaultObject: %s", desc.getName());
2522 try {
2523 final Object obj = desc.newInstance();
2524 if (!unshared)
2525 handles.setObject(passHandle, obj);
2526
2527 // Best effort Failure Atomicity; slotValues will be non-null if field
2528 // values can be set after reading all field data in the hierarchy.
2529 List<FieldValues> slotValues = desc.getClassDataLayout().stream()
2530 .filter(s -> s.hasData)
2531 .map(s1 -> {
2532 var values = new FieldValues(s1.desc, true);
2533 finishBlockData(s1.desc);
2534 return values;
2535 })
2536 .toList();
2537
2538 if (handles.lookupException(passHandle) != null) {
2539 return null; // some exception for a class, do not return the object
2540 }
2541
2542 // Check that the types are assignable for all slots before assigning.
2543 slotValues.forEach(v -> v.defaultCheckFieldValues(obj));
2544 slotValues.forEach(v -> v.defaultSetFieldValues(obj));
2545 return obj;
2546 } catch (InstantiationException | InvocationTargetException ex) {
2547 throw new InvalidClassException(desc.forClass().getName(),
2548 "unable to create instance", ex);
2549 }
2550 }
2551
2552
2553 /**
2554 * Reads (or attempts to skip, if not instantiatable or is tagged with a
2555 * ClassNotFoundException) instance data for each serializable class of
2556 * object in stream, from superclass to subclass.
2557 * Expects that passHandle is set to current handle before this method is called.
2558 */
2559 private Object readSerialCustomData(ObjectStreamClass desc, boolean unshared)
2560 throws IOException
2561 {
2562 if (!desc.isInstantiable()) {
2563 // No local class to create, read and discard
2564 return readAbsentLocalClass(desc, unshared);
2565 }
2566
2567 TRACE("readSerialCustomData: %s, ex: %s", desc.getName(), handles.lookupException(passHandle));
2568 try {
2569 Object obj = desc.newInstance();
2570 if (!unshared)
2571 handles.setObject(passHandle, obj);
2572 // Read data into each of the slots for the class
2573 return readSerialCustomSlots(obj, desc.getClassDataLayout());
2574 } catch (InstantiationException | InvocationTargetException ex) {
2575 throw new InvalidClassException(desc.forClass().getName(),
2576 "unable to create instance", ex);
2577 }
2578 }
2579
2580 /**
2581 * Reads from the stream using custom or default readObject methods appropriate.
2582 * For each slot, either the custom readObject method or the default reader of fields
2583 * is invoked. Unused slot specific custom data is discarded.
2584 * This function is used by {@link #readSerialCustomData}.
2585 *
2586 * @param obj the object to assign the values to
2587 * @param slots a list of slots to read from the stream
2588 * @return the object being initialized
2589 * @throws IOException if there are I/O errors while reading from the
2590 * underlying {@code InputStream}
2591 */
2592 private Object readSerialCustomSlots(Object obj, List<ClassDataSlot> slots) throws IOException {
2593 TRACE(" readSerialCustomSlots: %s", slots);
2594
2595 for (ClassDataSlot slot : slots) {
2596 ObjectStreamClass slotDesc = slot.desc;
2597 if (slot.hasData) {
2598 if (slotDesc.hasReadObjectMethod() &&
2599 handles.lookupException(passHandle) == null) {
2600 // Invoke slot custom readObject method
2601 readSlotViaReadObject(obj, slotDesc);
2602 } else {
2603 // Read fields of the current descriptor into a new FieldValues
2604 FieldValues values = new FieldValues(slotDesc, true);
2605 if (handles.lookupException(passHandle) == null) {
2606 // Set the instance fields if no previous exception
2607 values.defaultCheckFieldValues(obj);
2608 values.defaultSetFieldValues(obj);
2609 }
2610 finishBlockData(slotDesc);
2611 }
2612 } else {
2613 if (slotDesc.hasReadObjectNoDataMethod() &&
2614 handles.lookupException(passHandle) == null) {
2615 slotDesc.invokeReadObjectNoData(obj);
2616 }
2617 }
2618 }
2619 return obj;
2620 }
2621
2622 /**
2623 * Invoke the readObject method of the class to read and store the state from the stream.
2624 *
2625 * @param obj an instance of the class being created, only partially initialized.
2626 * @param slotDesc the ObjectStreamDescriptor for the current class
2627 * @throws IOException if there are I/O errors while reading from the
2628 * underlying {@code InputStream}
2629 */
2630 private void readSlotViaReadObject(Object obj, ObjectStreamClass slotDesc) throws IOException {
2631 TRACE("readSlotViaReadObject: %s", slotDesc.getName());
2632 assert obj != null : "readSlotViaReadObject called when obj == null";
2633
2634 SerialCallbackContext oldContext = curContext;
2635 if (oldContext != null)
2636 oldContext.check();
2637 try {
2638 curContext = new SerialCallbackContext(obj, slotDesc);
2639
2640 bin.setBlockDataMode(true);
2641 slotDesc.invokeReadObject(obj, this);
2642 } catch (ClassNotFoundException ex) {
2643 /*
2644 * In most cases, the handle table has already
2645 * propagated a CNFException to passHandle at this
2646 * point; this mark call is included to address cases
2647 * where the custom readObject method has cons'ed and
2648 * thrown a new CNFException of its own.
2649 */
2650 handles.markException(passHandle, ex);
2651 } finally {
2652 curContext.setUsed();
2653 if (oldContext!= null)
2654 oldContext.check();
2655 curContext = oldContext;
2656 }
2657
2658 /*
2659 * defaultDataEnd may have been set indirectly by custom
2660 * readObject() method when calling defaultReadObject() or
2661 * readFields(); clear it to restore normal read behavior.
2662 */
2663 defaultDataEnd = false;
2664
2665 finishBlockData(slotDesc);
2666 }
2667
2668
2669 /**
2670 * Read and discard an entire object, leaving a null reference in the HandleTable.
2671 * The descriptor of the class in the stream is used to read the fields from the stream.
2672 * There is no instance in which to store the field values.
2673 * Custom data following the fields of any slot is read and discarded.
2674 * References to nested objects are read and retained in the
2675 * handle table using the regular mechanism.
2676 * Handles later in the stream may refer to the nested objects.
2677 *
2678 * @param desc the stream class descriptor
2679 * @param unshared the unshared flag, ignored since no object is created
2680 * @return null, no object is created
2681 * @throws IOException if there are I/O errors while reading from the
2682 * underlying {@code InputStream}
2683 */
2684 private Object readAbsentLocalClass(ObjectStreamClass desc, boolean unshared)
2685 throws IOException {
2686 TRACE("readAbsentLocalClass: %s", desc.getName());
2687 desc.getClassDataLayout().stream()
2688 .filter(s -> s.hasData)
2689 .forEach(s2 -> {new FieldValues(s2.desc, true); finishBlockData(s2.desc);});
2690 return null;
2691 }
2692
2693 // Finish handling of block data by skipping any remaining and setting BlockDataMode = false
2694 private void finishBlockData(ObjectStreamClass slotDesc) throws UncheckedIOException {
2695 try {
2696 if (slotDesc.hasWriteObjectData()) {
2697 skipCustomData();
2698 } else {
2699 bin.setBlockDataMode(false);
2700 }
2701 } catch (IOException ioe) {
2702 throw new UncheckedIOException(ioe);
2703 }
2704 }
2705
2706 /**
2707 * Skips over all block data and objects until TC_ENDBLOCKDATA is
2708 * encountered.
2709 */
2710 private void skipCustomData() throws IOException {
2711 int oldHandle = passHandle;
2712 for (;;) {
2713 if (bin.getBlockDataMode()) {
2714 bin.skipBlockData();
2715 bin.setBlockDataMode(false);
2716 }
2717 switch (bin.peekByte()) {
2718 case TC_BLOCKDATA:
2719 case TC_BLOCKDATALONG:
2720 bin.setBlockDataMode(true);
2721 break;
2722
2778 /**
2779 * Default GetField implementation.
2780 */
2781 private final class FieldValues extends GetField {
2782
2783 /** class descriptor describing serializable fields */
2784 private final ObjectStreamClass desc;
2785 /** primitive field values */
2786 final byte[] primValues;
2787 /** object field values */
2788 final Object[] objValues;
2789 /** object field value handles */
2790 private final int[] objHandles;
2791
2792 /**
2793 * Creates FieldValues object for reading fields defined in given
2794 * class descriptor.
2795 * @param desc the ObjectStreamClass to read
2796 * @param recordDependencies if true, record the dependencies
2797 * from current PassHandle and the object's read.
2798 * @throws UncheckedIOException if any IOException occurs
2799 */
2800 FieldValues(ObjectStreamClass desc, boolean recordDependencies) throws UncheckedIOException {
2801 try {
2802 this.desc = desc;
2803 TRACE(" reading FieldValues: %s", desc.getName());
2804 int primDataSize = desc.getPrimDataSize();
2805 primValues = (primDataSize > 0) ? new byte[primDataSize] : null;
2806 if (primDataSize > 0) {
2807 bin.readFully(primValues, 0, primDataSize, false);
2808 }
2809
2810
2811 int numObjFields = desc.getNumObjFields();
2812 objValues = (numObjFields > 0) ? new Object[numObjFields] : null;
2813 objHandles = (numObjFields > 0) ? new int[numObjFields] : null;
2814 if (numObjFields > 0) {
2815 int objHandle = passHandle;
2816 ObjectStreamField[] fields = desc.getFields(false);
2817 int numPrimFields = fields.length - objValues.length;
2818 for (int i = 0; i < objValues.length; i++) {
2819 ObjectStreamField f = fields[numPrimFields + i];
2820 objValues[i] = readObject0(Object.class, f.isUnshared());
2821 objHandles[i] = passHandle;
2822 if (recordDependencies && f.getField() != null) {
2823 handles.markDependency(objHandle, passHandle);
2824 }
2825 }
2826 passHandle = objHandle;
2827 }
2828 } catch (IOException ioe) {
2829 throw new UncheckedIOException(ioe);
2830 }
2831 }
2832
2833 public ObjectStreamClass getObjectStreamClass() {
2834 return desc;
2835 }
2836
2837 public boolean defaulted(String name) {
2838 return (getFieldOffset(name, null) < 0);
2839 }
2840
2841 public boolean get(String name, boolean val) {
2842 int off = getFieldOffset(name, Boolean.TYPE);
2843 return (off >= 0) ? ByteArray.getBoolean(primValues, off) : val;
2844 }
2845
2846 public byte get(String name, byte val) {
2847 int off = getFieldOffset(name, Byte.TYPE);
2848 return (off >= 0) ? primValues[off] : val;
2849 }
|