1 /*
2 * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
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.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.List;
42 import java.util.Objects;
43
44 import jdk.internal.access.JavaLangAccess;
45 import jdk.internal.access.SharedSecrets;
46 import jdk.internal.event.DeserializationEvent;
47 import jdk.internal.misc.Unsafe;
48 import jdk.internal.util.ByteArray;
49
50 /**
51 * An ObjectInputStream deserializes primitive data and objects previously
52 * written using an ObjectOutputStream.
53 *
54 * <p><strong>Warning: Deserialization of untrusted data is inherently dangerous
55 * and should be avoided. Untrusted data should be carefully validated according to the
56 * "Serialization and Deserialization" section of the
57 * {@extLink secure_coding_guidelines_javase Secure Coding Guidelines for Java SE}.
58 * {@extLink serialization_filter_guide Serialization Filtering} describes best
59 * practices for defensive use of serial filters.
60 * </strong></p>
61 *
62 * <p>The key to disabling deserialization attacks is to prevent instances of
63 * arbitrary classes from being deserialized, thereby preventing the direct or
64 * indirect execution of their methods.
65 * {@link ObjectInputFilter} describes how to use filters and
66 * {@link ObjectInputFilter.Config} describes how to configure the filter and filter factory.
67 * Each stream has an optional deserialization filter
68 * to check the classes and resource limits during deserialization.
69 * The JVM-wide filter factory ensures that a filter can be set on every {@link ObjectInputStream}
70 * and every object read from the stream can be checked.
71 * The {@linkplain #ObjectInputStream() ObjectInputStream constructors} invoke the filter factory
72 * to select the initial filter which may be updated or replaced by {@link #setObjectInputFilter}.
73 * <p>
74 * If an ObjectInputStream has a filter, the {@link ObjectInputFilter} can check that
75 * the classes, array lengths, number of references in the stream, depth, and
76 * number of bytes consumed from the input stream are allowed and
77 * if not, can terminate deserialization.
78 *
79 * <p>ObjectOutputStream and ObjectInputStream can provide an application with
80 * persistent storage for graphs of objects when used with a FileOutputStream
81 * and FileInputStream respectively. ObjectInputStream is used to recover
82 * those objects previously serialized. Other uses include passing objects
83 * between hosts using a socket stream or for marshaling and unmarshaling
84 * arguments and parameters in a remote communication system.
85 *
86 * <p>ObjectInputStream ensures that the types of all objects in the graph
87 * created from the stream match the classes present in the Java Virtual
88 * Machine. Classes are loaded as required using the standard mechanisms.
89 *
90 * <p>Only objects that support the java.io.Serializable or
91 * java.io.Externalizable interface can be read from streams.
92 *
93 * <p>The method {@code readObject} is used to read an object from the
94 * stream. Java's safe casting should be used to get the desired type. In
95 * Java, strings and arrays are objects and are treated as objects during
96 * serialization. When read they need to be cast to the expected type.
97 *
98 * <p>Primitive data types can be read from the stream using the appropriate
99 * method on DataInput.
100 *
101 * <p>The default deserialization mechanism for objects restores the contents
102 * of each field to the value and type it had when it was written. Fields
103 * declared as transient or static are ignored by the deserialization process.
104 * References to other objects cause those objects to be read from the stream
105 * as necessary. Graphs of objects are restored correctly using a reference
106 * sharing mechanism. New objects are always allocated when deserializing,
107 * which prevents existing objects from being overwritten.
108 *
109 * <p>Reading an object is analogous to running the constructors of a new
110 * object. Memory is allocated for the object and initialized to zero (NULL).
111 * No-arg constructors are invoked for the non-serializable classes and then
112 * the fields of the serializable classes are restored from the stream starting
113 * with the serializable class closest to java.lang.object and finishing with
114 * the object's most specific class.
115 *
116 * <p>For example to read from a stream as written by the example in
117 * {@link ObjectOutputStream}:
118 * <br>
119 * {@snippet lang="java" :
120 * try (FileInputStream fis = new FileInputStream("t.tmp");
121 * ObjectInputStream ois = new ObjectInputStream(fis)) {
122 * String label = (String) ois.readObject();
123 * LocalDateTime dateTime = (LocalDateTime) ois.readObject();
124 * // Use label and dateTime
125 * } catch (Exception ex) {
126 * // handle exception
127 * }
128 * }
129 *
130 * <p>Classes control how they are serialized by implementing either the
131 * java.io.Serializable or java.io.Externalizable interfaces.
132 *
133 * <p>Implementing the Serializable interface allows object serialization to
134 * save and restore the entire state of the object and it allows classes to
135 * evolve between the time the stream is written and the time it is read. It
136 * automatically traverses references between objects, saving and restoring
137 * entire graphs.
138 *
139 * <p>Serializable classes that require special handling during the
140 * serialization and deserialization process should implement methods
141 * with the following signatures:
142 *
143 * {@snippet lang="java":
144 * private void writeObject(java.io.ObjectOutputStream stream)
145 * throws IOException;
146 * private void readObject(java.io.ObjectInputStream stream)
147 * throws IOException, ClassNotFoundException;
148 * private void readObjectNoData()
149 * throws ObjectStreamException;
150 * }
151 *
152 * <p>The method name, modifiers, return type, and number and type of
153 * parameters must match exactly for the method to be used by
154 * serialization or deserialization. The methods should only be
155 * declared to throw checked exceptions consistent with these
156 * signatures.
157 *
158 * <p>The readObject method is responsible for reading and restoring the state
159 * of the object for its particular class using data written to the stream by
160 * the corresponding writeObject method. The method does not need to concern
161 * itself with the state belonging to its superclasses or subclasses. State is
162 * restored by reading data from the ObjectInputStream for the individual
163 * fields and making assignments to the appropriate fields of the object.
164 * Reading primitive data types is supported by DataInput.
165 *
166 * <p>Any attempt to read object data which exceeds the boundaries of the
167 * custom data written by the corresponding writeObject method will cause an
168 * OptionalDataException to be thrown with an eof field value of true.
169 * Non-object reads which exceed the end of the allotted data will reflect the
170 * end of data in the same way that they would indicate the end of the stream:
171 * bytewise reads will return -1 as the byte read or number of bytes read, and
172 * primitive reads will throw EOFExceptions. If there is no corresponding
173 * writeObject method, then the end of default serialized data marks the end of
174 * the allotted data.
175 *
176 * <p>Primitive and object read calls issued from within a readExternal method
177 * behave in the same manner--if the stream is already positioned at the end of
178 * data written by the corresponding writeExternal method, object reads will
179 * throw OptionalDataExceptions with eof set to true, bytewise reads will
180 * return -1, and primitive reads will throw EOFExceptions. Note that this
181 * behavior does not hold for streams written with the old
182 * {@code ObjectStreamConstants.PROTOCOL_VERSION_1} protocol, in which the
183 * end of data written by writeExternal methods is not demarcated, and hence
184 * cannot be detected.
185 *
186 * <p>The readObjectNoData method is responsible for initializing the state of
187 * the object for its particular class in the event that the serialization
188 * stream does not list the given class as a superclass of the object being
189 * deserialized. This may occur in cases where the receiving party uses a
190 * different version of the deserialized instance's class than the sending
191 * party, and the receiver's version extends classes that are not extended by
192 * the sender's version. This may also occur if the serialization stream has
193 * been tampered; hence, readObjectNoData is useful for initializing
194 * deserialized objects properly despite a "hostile" or incomplete source
195 * stream.
196 *
197 * <p>Serialization does not read or assign values to the fields of any object
198 * that does not implement the java.io.Serializable interface. Subclasses of
199 * Objects that are not serializable can be serializable. In this case the
200 * non-serializable class must have a no-arg constructor to allow its fields to
201 * be initialized. In this case it is the responsibility of the subclass to
202 * save and restore the state of the non-serializable class. It is frequently
203 * the case that the fields of that class are accessible (public, package, or
204 * protected) or that there are get and set methods that can be used to restore
205 * the state.
206 *
207 * <p>Any exception that occurs while deserializing an object will be caught by
208 * the ObjectInputStream and abort the reading process.
209 *
210 * <p>Implementing the Externalizable interface allows the object to assume
211 * complete control over the contents and format of the object's serialized
212 * form. The methods of the Externalizable interface, writeExternal and
213 * readExternal, are called to save and restore the objects state. When
214 * implemented by a class they can write and read their own state using all of
215 * the methods of ObjectOutput and ObjectInput. It is the responsibility of
216 * the objects to handle any versioning that occurs.
217 * Value objects cannot be `java.io.Externalizable` because value objects are
218 * immutable and `Externalizable.readExternal` is unable to modify the fields of the value.
219 *
220 * <p>Enum constants are deserialized differently than ordinary serializable or
221 * externalizable objects. The serialized form of an enum constant consists
222 * solely of its name; field values of the constant are not transmitted. To
223 * deserialize an enum constant, ObjectInputStream reads the constant name from
224 * the stream; the deserialized constant is then obtained by calling the static
225 * method {@code Enum.valueOf(Class, String)} with the enum constant's
226 * base type and the received constant name as arguments. Like other
227 * serializable or externalizable objects, enum constants can function as the
228 * targets of back references appearing subsequently in the serialization
229 * stream. The process by which enum constants are deserialized cannot be
230 * customized: any class-specific readObject, readObjectNoData, and readResolve
231 * methods defined by enum types are ignored during deserialization.
232 * Similarly, any serialPersistentFields or serialVersionUID field declarations
233 * are also ignored--all enum types have a fixed serialVersionUID of 0L.
234 *
235 * <a id="record-serialization"></a>
236 * <p>Records are serialized differently than ordinary serializable or externalizable
237 * objects. During deserialization the record's canonical constructor is invoked
238 * to construct the record object. Certain serialization-related methods, such
239 * as readObject and writeObject, are ignored for serializable records. See
240 * <a href="{@docRoot}/../specs/serialization/serial-arch.html#serialization-of-records">
241 * <cite>Java Object Serialization Specification,</cite> Section 1.13,
242 * "Serialization of Records"</a> for additional information.
243 *
244 * <p>Value classes are {@linkplain Serializable} through the use of the serialization proxy pattern.
245 * See {@linkplain ObjectOutputStream##valueclass-serialization value class serialization} for details.
246 * When the proxy is deserialized it re-constructs and returns the value object.
247 *
248 * @spec serialization/index.html Java Object Serialization Specification
249 * @author Mike Warres
250 * @author Roger Riggs
251 * @see java.io.DataInput
252 * @see java.io.ObjectOutputStream
253 * @see java.io.Serializable
254 * @see <a href="{@docRoot}/../specs/serialization/input.html">
255 * <cite>Java Object Serialization Specification,</cite> Section 3, "Object Input Classes"</a>
256 * @since 1.1
257 */
258 public class ObjectInputStream
259 extends InputStream implements ObjectInput, ObjectStreamConstants
260 {
261 /** handle value representing null */
262 private static final int NULL_HANDLE = -1;
263
264 /** marker for unshared objects in internal handle table */
265 private static final Object unsharedMarker = new Object();
266
267 private static class Caches {
268
269 /**
270 * Property to permit setting a filter after objects
271 * have been read.
272 * See {@link #setObjectInputFilter(ObjectInputFilter)}
273 */
274 static final boolean SET_FILTER_AFTER_READ =
275 Boolean.getBoolean("jdk.serialSetFilterAfterRead");
276
277 /**
278 * Property to control {@link GetField#get(String, Object)} conversion of
279 * {@link ClassNotFoundException} to {@code null}. If set to {@code true}
280 * {@link GetField#get(String, Object)} returns null otherwise
281 * throwing {@link ClassNotFoundException}.
282 */
283 private static final boolean GETFIELD_CNFE_RETURNS_NULL =
284 Boolean.getBoolean("jdk.serialGetFieldCnfeReturnsNull");
285
286 /**
287 * Property to override the implementation limit on the number
288 * of interfaces allowed for Proxies. The property value is clamped to 0..65535.
289 * The maximum number of interfaces allowed for a proxy is limited to 65535 by
290 * {@link java.lang.reflect.Proxy#newProxyInstance(ClassLoader, Class[], InvocationHandler)}.
291 */
292 static final int PROXY_INTERFACE_LIMIT =
293 Math.clamp(Integer.getInteger("jdk.serialProxyInterfaceLimit", 65535), 0, 65535);
294 }
295
296 /*
297 * Separate class to defer initialization of logging until needed.
298 */
299 private static class Logging {
300 /*
301 * Logger for ObjectInputFilter results.
302 * Setup the filter logger if it is set to DEBUG or TRACE.
303 * (Assuming it will not change).
304 */
305 static final System.Logger filterLogger;
306
307 static {
308 Logger filterLog = System.getLogger("java.io.serialization");
309 filterLogger = (filterLog.isLoggable(Logger.Level.DEBUG)
310 || filterLog.isLoggable(Logger.Level.TRACE)) ? filterLog : null;
311 }
312 }
313
314 /** filter stream for handling block data conversion */
315 private final BlockDataInputStream bin;
316 /** validation callback list */
317 private final ValidationList vlist;
318 /** recursion depth */
319 private long depth;
320 /** Total number of references to any type of object, class, enum, proxy, etc. */
321 private long totalObjectRefs;
322 /** whether stream is closed */
323 private boolean closed;
324
325 /** wire handle -> obj/exception map */
326 private final HandleTable handles;
327 /** scratch field for passing handle values up/down call stack */
328 private int passHandle = NULL_HANDLE;
329 /** flag set when at end of field value block with no TC_ENDBLOCKDATA */
330 private boolean defaultDataEnd = false;
331
332 /** if true, invoke readObjectOverride() instead of readObject() */
333 private final boolean enableOverride;
334 /** if true, invoke resolveObject() */
335 private boolean enableResolve;
336
337 /**
338 * Context during upcalls to class-defined readObject methods; holds
339 * object currently being deserialized and descriptor for current class.
340 * Null when not during readObject upcall.
341 */
342 private SerialCallbackContext curContext;
343
344 /**
345 * Filter of class descriptors and classes read from the stream;
346 * may be null.
347 */
348 private ObjectInputFilter serialFilter;
349
350 /**
351 * True if the stream-specific filter has been set; initially false.
352 */
353 private boolean streamFilterSet;
354
355 /**
356 * Creates an ObjectInputStream that reads from the specified InputStream.
357 * A serialization stream header is read from the stream and verified.
358 * This constructor will block until the corresponding ObjectOutputStream
359 * has written and flushed the header.
360 *
361 * <p>The constructor initializes the deserialization filter to the filter returned
362 * by invoking the serial filter factory returned from {@link Config#getSerialFilterFactory()}
363 * with {@code null} for the current filter
364 * and the {@linkplain Config#getSerialFilter() static JVM-wide filter} for the requested filter.
365 * If the serial filter or serial filter factory properties are invalid
366 * an {@link IllegalStateException} is thrown.
367 * When the filter factory {@code apply} method is invoked it may throw a runtime exception
368 * preventing the {@code ObjectInputStream} from being constructed.
369 *
370 * @param in input stream to read from
371 * @throws StreamCorruptedException if the stream header is incorrect
372 * @throws IOException if an I/O error occurs while reading stream header
373 * @throws IllegalStateException if the initialization of {@link ObjectInputFilter.Config}
374 * fails due to invalid serial filter or serial filter factory properties.
375 * @throws NullPointerException if {@code in} is {@code null}
376 * @see ObjectInputStream#ObjectInputStream()
377 * @see ObjectInputStream#readFields()
378 * @see ObjectOutputStream#ObjectOutputStream(OutputStream)
379 */
380 @SuppressWarnings("this-escape")
381 public ObjectInputStream(InputStream in) throws IOException {
382 bin = new BlockDataInputStream(in);
383 handles = new HandleTable(10);
384 vlist = new ValidationList();
385 streamFilterSet = false;
386 serialFilter = Config.getSerialFilterFactorySingleton().apply(null, Config.getSerialFilter());
387 enableOverride = false;
388 readStreamHeader();
389 bin.setBlockDataMode(true);
390 }
391
392 /**
393 * Provide a way for subclasses that are completely reimplementing
394 * ObjectInputStream to not have to allocate private data just used by this
395 * implementation of ObjectInputStream.
396 *
397 * <p>The constructor initializes the deserialization filter to the filter returned
398 * by invoking the serial filter factory returned from {@link Config#getSerialFilterFactory()}
399 * with {@code null} for the current filter
400 * and the {@linkplain Config#getSerialFilter() static JVM-wide filter} for the requested filter.
401 * If the serial filter or serial filter factory properties are invalid
402 * an {@link IllegalStateException} is thrown.
403 * When the filter factory {@code apply} method is invoked it may throw a runtime exception
404 * preventing the {@code ObjectInputStream} from being constructed.
405 *
406 * @throws IOException if an I/O error occurs while creating this stream
407 * @throws IllegalStateException if the initialization of {@link ObjectInputFilter.Config}
408 * fails due to invalid serial filter or serial filter factory properties.
409 */
410 protected ObjectInputStream() throws IOException {
411 bin = null;
412 handles = null;
413 vlist = null;
414 streamFilterSet = false;
415 serialFilter = Config.getSerialFilterFactorySingleton().apply(null, Config.getSerialFilter());
416 enableOverride = true;
417 }
418
419 /**
420 * Read an object from the ObjectInputStream. The class of the object, the
421 * signature of the class, and the values of the non-transient and
422 * non-static fields of the class and all of its supertypes are read.
423 * Default deserializing for a class can be overridden using the writeObject
424 * and readObject methods. Objects referenced by this object are read
425 * transitively so that a complete equivalent graph of objects is
426 * reconstructed by readObject.
427 *
428 * <p>The root object is completely restored when all of its fields and the
429 * objects it references are completely restored. At this point the object
430 * validation callbacks are executed in order based on their registered
431 * priorities. The callbacks are registered by objects (in the readObject
432 * special methods) as they are individually restored.
433 *
434 * <p>The deserialization filter, when not {@code null}, is invoked for
435 * each object (regular or class) read to reconstruct the root object.
436 * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
437 *
438 * <p>Serialization and deserialization of value classes is described in
439 * {@linkplain ObjectOutputStream##valueclass-serialization value class serialization}.
440 *
441 * @implSpec
442 * When enabled with {@code --enable-preview}, serialization and deserialization of
443 * Core Library value classes migrated from pre-JEP 401 identity classes is
444 * implementation specific.
445 *
446 * <p>Exceptions are thrown for problems with the InputStream and for
447 * classes that should not be deserialized. All exceptions are fatal to
448 * the InputStream and leave it in an indeterminate state; it is up to the
449 * caller to ignore or recover the stream state.
450 *
451 * @throws ClassNotFoundException Class of a serialized object cannot be
452 * found.
453 * @throws InvalidClassException Something is wrong with a class used by
454 * deserialization.
455 * @throws StreamCorruptedException Control information in the
456 * stream is inconsistent.
457 * @throws OptionalDataException Primitive data was found in the
458 * stream instead of objects.
459 * @throws IOException Any of the usual Input/Output related exceptions.
460 */
461 public final Object readObject()
462 throws IOException, ClassNotFoundException {
463 return readObject(Object.class);
464 }
465
466 /**
467 * Reads a String and only a string.
468 *
469 * @return the String read
470 * @throws EOFException If end of file is reached.
471 * @throws IOException If other I/O error has occurred.
472 */
473 private String readString() throws IOException {
474 try {
475 return (String) readObject(String.class);
476 } catch (ClassNotFoundException cnf) {
477 throw new IllegalStateException(cnf);
478 }
479 }
480
481 /**
482 * Internal method to read an object from the ObjectInputStream of the expected type.
483 * Called only from {@code readObject()} and {@code readString()}.
484 * Only {@code Object.class} and {@code String.class} are supported.
485 *
486 * @param type the type expected; either Object.class or String.class
487 * @return an object of the type
488 * @throws IOException Any of the usual Input/Output related exceptions.
489 * @throws ClassNotFoundException Class of a serialized object cannot be
490 * found.
491 */
492 private final Object readObject(Class<?> type)
493 throws IOException, ClassNotFoundException
494 {
495 if (enableOverride) {
496 return readObjectOverride();
497 }
498
499 if (! (type == Object.class || type == String.class))
500 throw new AssertionError("internal error");
501
502 // if nested read, passHandle contains handle of enclosing object
503 int outerHandle = passHandle;
504 try {
505 Object obj = readObject0(type, false);
506 handles.markDependency(outerHandle, passHandle);
507 ClassNotFoundException ex = handles.lookupException(passHandle);
508 if (ex != null) {
509 throw ex;
510 }
511 if (depth == 0) {
512 vlist.doCallbacks();
513 freeze();
514 }
515 return obj;
516 } finally {
517 passHandle = outerHandle;
518 if (closed && depth == 0) {
519 clear();
520 }
521 }
522 }
523
524 /**
525 * This method is called by trusted subclasses of ObjectInputStream that
526 * constructed ObjectInputStream using the protected no-arg constructor.
527 * The subclass is expected to provide an override method with the modifier
528 * "final".
529 *
530 * @return the Object read from the stream.
531 * @throws ClassNotFoundException Class definition of a serialized object
532 * cannot be found.
533 * @throws OptionalDataException Primitive data was found in the stream
534 * instead of objects.
535 * @throws IOException if I/O errors occurred while reading from the
536 * underlying stream
537 * @see #ObjectInputStream()
538 * @see #readObject()
539 * @since 1.2
540 */
541 protected Object readObjectOverride()
542 throws IOException, ClassNotFoundException
543 {
544 return null;
545 }
546
547 /**
548 * Reads an "unshared" object from the ObjectInputStream. This method is
549 * identical to readObject, except that it prevents subsequent calls to
550 * readObject and readUnshared from returning additional references to the
551 * deserialized instance obtained via this call. Specifically:
552 * <ul>
553 * <li>If readUnshared is called to deserialize a back-reference (the
554 * stream representation of an object which has been written
555 * previously to the stream), an ObjectStreamException will be
556 * thrown.
557 *
558 * <li>If readUnshared returns successfully, then any subsequent attempts
559 * to deserialize back-references to the stream handle deserialized
560 * by readUnshared will cause an ObjectStreamException to be thrown.
561 * </ul>
562 * Deserializing an object via readUnshared invalidates the stream handle
563 * associated with the returned object. Note that this in itself does not
564 * always guarantee that the reference returned by readUnshared is unique;
565 * the deserialized object may define a readResolve method which returns an
566 * object visible to other parties, or readUnshared may return a Class
567 * object or enum constant obtainable elsewhere in the stream or through
568 * external means. If the deserialized object defines a readResolve method
569 * and the invocation of that method returns an array, then readUnshared
570 * returns a shallow clone of that array; this guarantees that the returned
571 * array object is unique and cannot be obtained a second time from an
572 * invocation of readObject or readUnshared on the ObjectInputStream,
573 * even if the underlying data stream has been manipulated.
574 *
575 * <p>The deserialization filter, when not {@code null}, is invoked for
576 * each object (regular or class) read to reconstruct the root object.
577 * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
578 *
579 * @return reference to deserialized object
580 * @throws ClassNotFoundException if class of an object to deserialize
581 * cannot be found
582 * @throws StreamCorruptedException if control information in the stream
583 * is inconsistent
584 * @throws ObjectStreamException if object to deserialize has already
585 * appeared in stream
586 * @throws OptionalDataException if primitive data is next in stream
587 * @throws IOException if an I/O error occurs during deserialization
588 * @since 1.4
589 */
590 public Object readUnshared() throws IOException, ClassNotFoundException {
591 // if nested read, passHandle contains handle of enclosing object
592 int outerHandle = passHandle;
593 try {
594 Object obj = readObject0(Object.class, true);
595 handles.markDependency(outerHandle, passHandle);
596 ClassNotFoundException ex = handles.lookupException(passHandle);
597 if (ex != null) {
598 throw ex;
599 }
600 if (depth == 0) {
601 vlist.doCallbacks();
602 freeze();
603 }
604 return obj;
605 } finally {
606 passHandle = outerHandle;
607 if (closed && depth == 0) {
608 clear();
609 }
610 }
611 }
612
613 /**
614 * Read the non-static and non-transient fields of the current class from
615 * this stream. This may only be called from the readObject method of the
616 * class being deserialized. It will throw the NotActiveException if it is
617 * called otherwise.
618 *
619 * @throws ClassNotFoundException if the class of a serialized object
620 * could not be found.
621 * @throws IOException if an I/O error occurs.
622 * @throws NotActiveException if the stream is not currently reading
623 * objects.
624 */
625 public void defaultReadObject()
626 throws IOException, ClassNotFoundException
627 {
628 SerialCallbackContext ctx = curContext;
629 if (ctx == null) {
630 throw new NotActiveException("not in call to readObject");
631 }
632 Object curObj = ctx.getObj();
633 ObjectStreamClass curDesc = ctx.getDesc();
634 bin.setBlockDataMode(false);
635
636 // Read fields of the current descriptor into a new FieldValues
637 FieldValues values = new FieldValues(curDesc, true);
638 if (curObj != null) {
639 values.defaultCheckFieldValues(curObj);
640 values.defaultSetFieldValues(curObj);
641 }
642 bin.setBlockDataMode(true);
643 if (!curDesc.hasWriteObjectData()) {
644 /*
645 * Fix for 4360508: since stream does not contain terminating
646 * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
647 * knows to simulate end-of-custom-data behavior.
648 */
649 defaultDataEnd = true;
650 }
651 ClassNotFoundException ex = handles.lookupException(passHandle);
652 if (ex != null) {
653 throw ex;
654 }
655 }
656
657 /**
658 * Reads the persistent fields from the stream and makes them available by
659 * name.
660 *
661 * @return the {@code GetField} object representing the persistent
662 * fields of the object being deserialized
663 * @throws ClassNotFoundException if the class of a serialized object
664 * could not be found.
665 * @throws IOException if an I/O error occurs.
666 * @throws NotActiveException if the stream is not currently reading
667 * objects.
668 * @since 1.2
669 */
670 public ObjectInputStream.GetField readFields()
671 throws IOException, ClassNotFoundException
672 {
673 SerialCallbackContext ctx = curContext;
674 if (ctx == null) {
675 throw new NotActiveException("not in call to readObject");
676 }
677 ctx.checkAndSetUsed();
678 ObjectStreamClass curDesc = ctx.getDesc();
679 bin.setBlockDataMode(false);
680 // Read fields of the current descriptor into a new FieldValues
681 FieldValues values = new FieldValues(curDesc, false);
682 bin.setBlockDataMode(true);
683 if (!curDesc.hasWriteObjectData()) {
684 /*
685 * Fix for 4360508: since stream does not contain terminating
686 * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
687 * knows to simulate end-of-custom-data behavior.
688 */
689 defaultDataEnd = true;
690 }
691 return values;
692 }
693
694 /**
695 * Register an object to be validated before the graph is returned. While
696 * similar to resolveObject these validations are called after the entire
697 * graph has been reconstituted. Typically, a readObject method will
698 * register the object with the stream so that when all of the objects are
699 * restored a final set of validations can be performed.
700 *
701 * @param obj the object to receive the validation callback.
702 * @param prio controls the order of callbacks; zero is a good default.
703 * Use higher numbers to be called back earlier, lower numbers for
704 * later callbacks. Within a priority, callbacks are processed in
705 * no particular order.
706 * @throws NotActiveException The stream is not currently reading objects
707 * so it is invalid to register a callback.
708 * @throws InvalidObjectException The validation object is null.
709 */
710 public void registerValidation(ObjectInputValidation obj, int prio)
711 throws NotActiveException, InvalidObjectException
712 {
713 if (depth == 0) {
714 throw new NotActiveException("stream inactive");
715 }
716 vlist.register(obj, prio);
717 }
718
719 /**
720 * Load the local class equivalent of the specified stream class
721 * description. Subclasses may implement this method to allow classes to
722 * be fetched from an alternate source.
723 *
724 * <p>The corresponding method in {@code ObjectOutputStream} is
725 * {@code annotateClass}. This method will be invoked only once for
726 * each unique class in the stream. This method can be implemented by
727 * subclasses to use an alternate loading mechanism but must return a
728 * {@code Class} object. Once returned, if the class is not an array
729 * class, its serialVersionUID is compared to the serialVersionUID of the
730 * serialized class, and if there is a mismatch, the deserialization fails
731 * and an {@link InvalidClassException} is thrown.
732 *
733 * <p>The default implementation of this method in
734 * {@code ObjectInputStream} returns the result of calling
735 * {@snippet lang="java":
736 * Class.forName(desc.getName(), false, loader)
737 * }
738 * where {@code loader} is the first class loader on the current
739 * thread's stack (starting from the currently executing method) that is
740 * neither the {@linkplain ClassLoader#getPlatformClassLoader() platform
741 * class loader} nor its ancestor; otherwise, {@code loader} is the
742 * <em>platform class loader</em>. If this call results in a
743 * {@code ClassNotFoundException} and the name of the passed
744 * {@code ObjectStreamClass} instance is the Java language keyword
745 * for a primitive type or void, then the {@code Class} object
746 * representing that primitive type or void will be returned
747 * (e.g., an {@code ObjectStreamClass} with the name
748 * {@code "int"} will be resolved to {@code Integer.TYPE}).
749 * Otherwise, the {@code ClassNotFoundException} will be thrown to
750 * the caller of this method.
751 *
752 * @param desc an instance of class {@code ObjectStreamClass}
753 * @return a {@code Class} object corresponding to {@code desc}
754 * @throws IOException any of the usual Input/Output exceptions.
755 * @throws ClassNotFoundException if class of a serialized object cannot
756 * be found.
757 */
758 protected Class<?> resolveClass(ObjectStreamClass desc)
759 throws IOException, ClassNotFoundException
760 {
761 String name = desc.getName();
762 try {
763 return Class.forName(name, false, latestUserDefinedLoader());
764 } catch (ClassNotFoundException ex) {
765 Class<?> cl = Class.forPrimitiveName(name);
766 if (cl != null) {
767 return cl;
768 } else {
769 throw ex;
770 }
771 }
772 }
773
774 /**
775 * Returns a proxy class that implements the interfaces named in a proxy
776 * class descriptor; subclasses may implement this method to read custom
777 * data from the stream along with the descriptors for dynamic proxy
778 * classes, allowing them to use an alternate loading mechanism for the
779 * interfaces and the proxy class.
780 *
781 * <p>This method is called exactly once for each unique proxy class
782 * descriptor in the stream.
783 *
784 * <p>The corresponding method in {@code ObjectOutputStream} is
785 * {@code annotateProxyClass}. For a given subclass of
786 * {@code ObjectInputStream} that overrides this method, the
787 * {@code annotateProxyClass} method in the corresponding subclass of
788 * {@code ObjectOutputStream} must write any data or objects read by
789 * this method.
790 *
791 * <p>The default implementation of this method in
792 * {@code ObjectInputStream} returns the result of calling
793 * {@code Proxy.getProxyClass} with the list of {@code Class}
794 * objects for the interfaces that are named in the {@code interfaces}
795 * parameter. The {@code Class} object for each interface name
796 * {@code i} is the value returned by calling
797 * {@snippet lang="java":
798 * Class.forName(i, false, loader)
799 * }
800 * where {@code loader} is the first class loader on the current
801 * thread's stack (starting from the currently executing method) that is
802 * neither the {@linkplain ClassLoader#getPlatformClassLoader() platform
803 * class loader} nor its ancestor; otherwise, {@code loader} is the
804 * <em>platform class loader</em>.
805 * Unless any of the resolved interfaces are non-public, this same value
806 * of {@code loader} is also the class loader passed to
807 * {@code Proxy.getProxyClass}; if non-public interfaces are present,
808 * their class loader is passed instead (if more than one non-public
809 * interface class loader is encountered, an
810 * {@code IllegalAccessError} is thrown).
811 * If {@code Proxy.getProxyClass} throws an
812 * {@code IllegalArgumentException}, {@code resolveProxyClass}
813 * will throw a {@code ClassNotFoundException} containing the
814 * {@code IllegalArgumentException}.
815 *
816 * @param interfaces the list of interface names that were
817 * deserialized in the proxy class descriptor
818 * @return a proxy class for the specified interfaces
819 * @throws IOException any exception thrown by the underlying
820 * {@code InputStream}
821 * @throws ClassNotFoundException if the proxy class or any of the
822 * named interfaces could not be found
823 * @see ObjectOutputStream#annotateProxyClass(Class)
824 * @since 1.3
825 */
826 protected Class<?> resolveProxyClass(String[] interfaces)
827 throws IOException, ClassNotFoundException
828 {
829 ClassLoader latestLoader = latestUserDefinedLoader();
830 ClassLoader nonPublicLoader = null;
831 boolean hasNonPublicInterface = false;
832
833 // define proxy in class loader of non-public interface(s), if any
834 Class<?>[] classObjs = new Class<?>[interfaces.length];
835 for (int i = 0; i < interfaces.length; i++) {
836 Class<?> cl = Class.forName(interfaces[i], false, latestLoader);
837 if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
838 if (hasNonPublicInterface) {
839 if (nonPublicLoader != cl.getClassLoader()) {
840 throw new IllegalAccessError(
841 "conflicting non-public interface class loaders");
842 }
843 } else {
844 nonPublicLoader = cl.getClassLoader();
845 hasNonPublicInterface = true;
846 }
847 }
848 classObjs[i] = cl;
849 }
850 try {
851 @SuppressWarnings("deprecation")
852 Class<?> proxyClass = Proxy.getProxyClass(
853 hasNonPublicInterface ? nonPublicLoader : latestLoader,
854 classObjs);
855 return proxyClass;
856 } catch (IllegalArgumentException e) {
857 throw new ClassNotFoundException(null, e);
858 }
859 }
860
861 /**
862 * This method will allow trusted subclasses of ObjectInputStream to
863 * substitute one object for another during deserialization. Replacing
864 * objects is disabled until enableResolveObject is called. The
865 * enableResolveObject method checks that the stream requesting to resolve
866 * object can be trusted. Every reference to serializable objects is passed
867 * to resolveObject. To ensure that the private state of objects is not
868 * unintentionally exposed only trusted streams may use resolveObject.
869 *
870 * <p>This method is called after an object has been read but before it is
871 * returned from readObject. The default resolveObject method just returns
872 * the same object.
873 *
874 * <p>When a subclass is replacing objects it must ensure that the
875 * substituted object is compatible with every field where the reference
876 * will be stored. Objects whose type is not a subclass of the type of the
877 * field or array element abort the deserialization by raising an exception
878 * and the object is not be stored.
879 *
880 * <p>This method is called only once when each object is first
881 * encountered. All subsequent references to the object will be redirected
882 * to the new object.
883 *
884 * @param obj object to be substituted
885 * @return the substituted object
886 * @throws IOException Any of the usual Input/Output exceptions.
887 */
888 protected Object resolveObject(Object obj) throws IOException {
889 return obj;
890 }
891
892 /**
893 * Enables the stream to do replacement of objects read from the stream. When
894 * enabled, the {@link #resolveObject} method is called for every object being
895 * deserialized.
896 *
897 * @param enable true for enabling use of {@code resolveObject} for
898 * every object being deserialized
899 * @return the previous setting before this method was invoked
900 */
901 protected boolean enableResolveObject(boolean enable) {
902 if (enable == enableResolve) {
903 return enable;
904 }
905 enableResolve = enable;
906 return !enableResolve;
907 }
908
909 /**
910 * The readStreamHeader method is provided to allow subclasses to read and
911 * verify their own stream headers. It reads and verifies the magic number
912 * and version number.
913 *
914 * @throws IOException if there are I/O errors while reading from the
915 * underlying {@code InputStream}
916 * @throws StreamCorruptedException if control information in the stream
917 * is inconsistent
918 */
919 protected void readStreamHeader()
920 throws IOException, StreamCorruptedException
921 {
922 short s0 = bin.readShort();
923 short s1 = bin.readShort();
924 if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) {
925 throw new StreamCorruptedException(
926 String.format("invalid stream header: %04X%04X", s0, s1));
927 }
928 }
929
930 /**
931 * Read a class descriptor from the serialization stream. This method is
932 * called when the ObjectInputStream expects a class descriptor as the next
933 * item in the serialization stream. Subclasses of ObjectInputStream may
934 * override this method to read in class descriptors that have been written
935 * in non-standard formats (by subclasses of ObjectOutputStream which have
936 * overridden the {@code writeClassDescriptor} method). By default,
937 * this method reads class descriptors according to the format defined in
938 * the Object Serialization specification.
939 *
940 * @return the class descriptor read
941 * @throws IOException If an I/O error has occurred.
942 * @throws ClassNotFoundException If the Class of a serialized object used
943 * in the class descriptor representation cannot be found
944 * @see java.io.ObjectOutputStream#writeClassDescriptor(java.io.ObjectStreamClass)
945 * @since 1.3
946 */
947 protected ObjectStreamClass readClassDescriptor()
948 throws IOException, ClassNotFoundException
949 {
950 ObjectStreamClass desc = new ObjectStreamClass();
951 desc.readNonProxy(this);
952 return desc;
953 }
954
955 /**
956 * Reads a byte of data. This method will block if no input is available.
957 *
958 * @return the byte read, or -1 if the end of the stream is reached.
959 * @throws IOException {@inheritDoc}
960 */
961 @Override
962 public int read() throws IOException {
963 return bin.read();
964 }
965
966 /**
967 * Reads into an array of bytes. This method will block until some input
968 * is available. Consider using java.io.DataInputStream.readFully to read
969 * exactly 'length' bytes.
970 *
971 * @param buf the buffer into which the data is read
972 * @param off the start offset in the destination array {@code buf}
973 * @param len the maximum number of bytes read
974 * @return the total number of bytes read into the buffer, or
975 * {@code -1} if there is no more data because the end of
976 * the stream has been reached.
977 * @throws NullPointerException if {@code buf} is {@code null}.
978 * @throws IndexOutOfBoundsException if {@code off} is negative,
979 * {@code len} is negative, or {@code len} is greater than
980 * {@code buf.length - off}.
981 * @throws IOException If an I/O error has occurred.
982 * @see java.io.DataInputStream#readFully(byte[],int,int)
983 */
984 @Override
985 public int read(byte[] buf, int off, int len) throws IOException {
986 if (buf == null) {
987 throw new NullPointerException();
988 }
989 Objects.checkFromIndexSize(off, len, buf.length);
990 return bin.read(buf, off, len, false);
991 }
992
993 /**
994 * Returns the number of bytes that can be read without blocking.
995 *
996 * @return the number of available bytes.
997 * @throws IOException if there are I/O errors while reading from the
998 * underlying {@code InputStream}
999 */
1000 @Override
1001 public int available() throws IOException {
1002 return bin.available();
1003 }
1004
1005 /**
1006 * {@inheritDoc}
1007 *
1008 * @throws IOException {@inheritDoc}
1009 */
1010 @Override
1011 public void close() throws IOException {
1012 /*
1013 * Even if stream already closed, propagate redundant close to
1014 * underlying stream to stay consistent with previous implementations.
1015 */
1016 closed = true;
1017 if (depth == 0) {
1018 clear();
1019 }
1020 bin.close();
1021 }
1022
1023 /**
1024 * Reads in a boolean.
1025 *
1026 * @return the boolean read.
1027 * @throws EOFException If end of file is reached.
1028 * @throws IOException If other I/O error has occurred.
1029 */
1030 public boolean readBoolean() throws IOException {
1031 return bin.readBoolean();
1032 }
1033
1034 /**
1035 * Reads an 8-bit byte.
1036 *
1037 * @return the 8-bit byte read.
1038 * @throws EOFException If end of file is reached.
1039 * @throws IOException If other I/O error has occurred.
1040 */
1041 public byte readByte() throws IOException {
1042 return bin.readByte();
1043 }
1044
1045 /**
1046 * Reads an unsigned 8-bit byte.
1047 *
1048 * @return the 8-bit byte read.
1049 * @throws EOFException If end of file is reached.
1050 * @throws IOException If other I/O error has occurred.
1051 */
1052 public int readUnsignedByte() throws IOException {
1053 return bin.readUnsignedByte();
1054 }
1055
1056 /**
1057 * Reads a 16-bit char.
1058 *
1059 * @return the 16-bit char read.
1060 * @throws EOFException If end of file is reached.
1061 * @throws IOException If other I/O error has occurred.
1062 */
1063 public char readChar() throws IOException {
1064 return bin.readChar();
1065 }
1066
1067 /**
1068 * Reads a 16-bit short.
1069 *
1070 * @return the 16-bit short read.
1071 * @throws EOFException If end of file is reached.
1072 * @throws IOException If other I/O error has occurred.
1073 */
1074 public short readShort() throws IOException {
1075 return bin.readShort();
1076 }
1077
1078 /**
1079 * Reads an unsigned 16-bit short.
1080 *
1081 * @return the 16-bit short read.
1082 * @throws EOFException If end of file is reached.
1083 * @throws IOException If other I/O error has occurred.
1084 */
1085 public int readUnsignedShort() throws IOException {
1086 return bin.readUnsignedShort();
1087 }
1088
1089 /**
1090 * Reads a 32-bit int.
1091 *
1092 * @return the 32-bit integer read.
1093 * @throws EOFException If end of file is reached.
1094 * @throws IOException If other I/O error has occurred.
1095 */
1096 public int readInt() throws IOException {
1097 return bin.readInt();
1098 }
1099
1100 /**
1101 * Reads a 64-bit long.
1102 *
1103 * @return the read 64-bit long.
1104 * @throws EOFException If end of file is reached.
1105 * @throws IOException If other I/O error has occurred.
1106 */
1107 public long readLong() throws IOException {
1108 return bin.readLong();
1109 }
1110
1111 /**
1112 * Reads a 32-bit float.
1113 *
1114 * @return the 32-bit float read.
1115 * @throws EOFException If end of file is reached.
1116 * @throws IOException If other I/O error has occurred.
1117 */
1118 public float readFloat() throws IOException {
1119 return bin.readFloat();
1120 }
1121
1122 /**
1123 * Reads a 64-bit double.
1124 *
1125 * @return the 64-bit double read.
1126 * @throws EOFException If end of file is reached.
1127 * @throws IOException If other I/O error has occurred.
1128 */
1129 public double readDouble() throws IOException {
1130 return bin.readDouble();
1131 }
1132
1133 /**
1134 * Reads bytes, blocking until all bytes are read.
1135 *
1136 * @param buf the buffer into which the data is read
1137 * @throws NullPointerException If {@code buf} is {@code null}.
1138 * @throws EOFException If end of file is reached.
1139 * @throws IOException If other I/O error has occurred.
1140 */
1141 public void readFully(byte[] buf) throws IOException {
1142 bin.readFully(buf, 0, buf.length, false);
1143 }
1144
1145 /**
1146 * Reads bytes, blocking until all bytes are read.
1147 *
1148 * @param buf the buffer into which the data is read
1149 * @param off the start offset into the data array {@code buf}
1150 * @param len the maximum number of bytes to read
1151 * @throws NullPointerException If {@code buf} is {@code null}.
1152 * @throws IndexOutOfBoundsException If {@code off} is negative,
1153 * {@code len} is negative, or {@code len} is greater than
1154 * {@code buf.length - off}.
1155 * @throws EOFException If end of file is reached.
1156 * @throws IOException If other I/O error has occurred.
1157 */
1158 public void readFully(byte[] buf, int off, int len) throws IOException {
1159 Objects.checkFromIndexSize(off, len, buf.length);
1160 bin.readFully(buf, off, len, false);
1161 }
1162
1163 /**
1164 * Skips bytes.
1165 *
1166 * @param len the number of bytes to be skipped
1167 * @return the actual number of bytes skipped.
1168 * @throws IOException If an I/O error has occurred.
1169 */
1170 @Override
1171 public int skipBytes(int len) throws IOException {
1172 return bin.skipBytes(len);
1173 }
1174
1175 /**
1176 * Reads in a line that has been terminated by a \n, \r, \r\n or EOF.
1177 *
1178 * @return a String copy of the line.
1179 * @throws IOException if there are I/O errors while reading from the
1180 * underlying {@code InputStream}
1181 * @deprecated This method does not properly convert bytes to characters.
1182 * see DataInputStream for the details and alternatives.
1183 */
1184 @Deprecated
1185 public String readLine() throws IOException {
1186 return bin.readLine();
1187 }
1188
1189 /**
1190 * Reads a String in
1191 * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
1192 * format.
1193 *
1194 * @return the String.
1195 * @throws IOException if there are I/O errors while reading from the
1196 * underlying {@code InputStream}
1197 * @throws UTFDataFormatException if read bytes do not represent a valid
1198 * modified UTF-8 encoding of a string
1199 */
1200 public String readUTF() throws IOException {
1201 return bin.readUTF();
1202 }
1203
1204 /**
1205 * Returns the deserialization filter for this stream.
1206 * The filter is the result of invoking the
1207 * {@link Config#getSerialFilterFactory() JVM-wide filter factory}
1208 * either by the {@linkplain #ObjectInputStream() constructor} or the most recent invocation of
1209 * {@link #setObjectInputFilter setObjectInputFilter}.
1210 *
1211 * @return the deserialization filter for the stream; may be null
1212 * @since 9
1213 */
1214 public final ObjectInputFilter getObjectInputFilter() {
1215 return serialFilter;
1216 }
1217
1218 /**
1219 * Set the deserialization filter for the stream.
1220 *
1221 * The deserialization filter is set to the filter returned by invoking the
1222 * {@linkplain Config#getSerialFilterFactory() JVM-wide filter factory}
1223 * with the {@linkplain #getObjectInputFilter() current filter} and the {@code filter} parameter.
1224 * The current filter was set in the
1225 * {@linkplain #ObjectInputStream() ObjectInputStream constructors} by invoking the
1226 * {@linkplain Config#getSerialFilterFactory() JVM-wide filter factory} and may be {@code null}.
1227 * {@linkplain #setObjectInputFilter(ObjectInputFilter)} This method} can be called
1228 * once and only once before reading any objects from the stream;
1229 * for example, by calling {@link #readObject} or {@link #readUnshared}.
1230 *
1231 * <p>It is not permitted to replace a {@code non-null} filter with a {@code null} filter.
1232 * If the {@linkplain #getObjectInputFilter() current filter} is {@code non-null},
1233 * the value returned from the filter factory must be {@code non-null}.
1234 *
1235 * <p>The filter's {@link ObjectInputFilter#checkInput checkInput} method is called
1236 * for each class and reference in the stream.
1237 * The filter can check any or all of the class, the array length, the number
1238 * of references, the depth of the graph, and the size of the input stream.
1239 * The depth is the number of nested {@linkplain #readObject readObject}
1240 * calls starting with the reading of the root of the graph being deserialized
1241 * and the current object being deserialized.
1242 * The number of references is the cumulative number of objects and references
1243 * to objects already read from the stream including the current object being read.
1244 * The filter is invoked only when reading objects from the stream and not for
1245 * primitives.
1246 * <p>
1247 * If the filter returns {@link ObjectInputFilter.Status#REJECTED Status.REJECTED},
1248 * {@code null} or throws a {@link RuntimeException},
1249 * the active {@code readObject} or {@code readUnshared}
1250 * throws {@link InvalidClassException}, otherwise deserialization
1251 * continues uninterrupted.
1252 *
1253 * @implSpec
1254 * The filter, when not {@code null}, is invoked during {@link #readObject readObject}
1255 * and {@link #readUnshared readUnshared} for each object (regular or class) in the stream.
1256 * Strings are treated as primitives and do not invoke the filter.
1257 * The filter is called for:
1258 * <ul>
1259 * <li>each object reference previously deserialized from the stream
1260 * (class is {@code null}, arrayLength is -1),
1261 * <li>each regular class (class is not {@code null}, arrayLength is -1),
1262 * <li>each interface class explicitly referenced in the stream
1263 * (it is not called for interfaces implemented by classes in the stream),
1264 * <li>each interface of a dynamic proxy and the dynamic proxy class itself
1265 * (class is not {@code null}, arrayLength is -1),
1266 * <li>each array is filtered using the array type and length of the array
1267 * (class is the array type, arrayLength is the requested length),
1268 * <li>each object replaced by its class' {@code readResolve} method
1269 * is filtered using the replacement object's class, if not {@code null},
1270 * and if it is an array, the arrayLength, otherwise -1,
1271 * <li>and each object replaced by {@link #resolveObject resolveObject}
1272 * is filtered using the replacement object's class, if not {@code null},
1273 * and if it is an array, the arrayLength, otherwise -1.
1274 * </ul>
1275 *
1276 * When the {@link ObjectInputFilter#checkInput checkInput} method is invoked
1277 * it is given access to the current class, the array length,
1278 * the current number of references already read from the stream,
1279 * the depth of nested calls to {@link #readObject readObject} or
1280 * {@link #readUnshared readUnshared},
1281 * and the implementation dependent number of bytes consumed from the input stream.
1282 * <p>
1283 * Each call to {@link #readObject readObject} or
1284 * {@link #readUnshared readUnshared} increases the depth by 1
1285 * before reading an object and decreases by 1 before returning
1286 * normally or exceptionally.
1287 * The depth starts at {@code 1} and increases for each nested object and
1288 * decrements when each nested call returns.
1289 * The count of references in the stream starts at {@code 1} and
1290 * is increased before reading an object.
1291 *
1292 * @param filter the filter, may be null
1293 * @throws IllegalStateException if an object has been read,
1294 * if the filter factory returns {@code null} when the
1295 * {@linkplain #getObjectInputFilter() current filter} is non-null, or
1296 * if the filter has already been set.
1297 * @since 9
1298 */
1299 public final void setObjectInputFilter(ObjectInputFilter filter) {
1300 if (totalObjectRefs > 0 && !Caches.SET_FILTER_AFTER_READ) {
1301 throw new IllegalStateException(
1302 "filter can not be set after an object has been read");
1303 }
1304 if (streamFilterSet) {
1305 throw new IllegalStateException("filter can not be set more than once");
1306 }
1307 streamFilterSet = true;
1308 // Delegate to serialFilterFactory to compute stream filter
1309 ObjectInputFilter next = Config.getSerialFilterFactory()
1310 .apply(serialFilter, filter);
1311 if (serialFilter != null && next == null) {
1312 throw new IllegalStateException("filter can not be replaced with null filter");
1313 }
1314 serialFilter = next;
1315 }
1316
1317 /**
1318 * Invokes the deserialization filter if non-null.
1319 *
1320 * If the filter rejects or an exception is thrown, throws InvalidClassException.
1321 *
1322 * Logs and/or commits a {@code DeserializationEvent}, if configured.
1323 *
1324 * @param clazz the class; may be null
1325 * @param arrayLength the array length requested; use {@code -1} if not creating an array
1326 * @throws InvalidClassException if it rejected by the filter or
1327 * a {@link RuntimeException} is thrown
1328 */
1329 private void filterCheck(Class<?> clazz, int arrayLength)
1330 throws InvalidClassException {
1331 // Info about the stream is not available if overridden by subclass, return 0
1332 long bytesRead = (bin == null) ? 0 : bin.getBytesRead();
1333 RuntimeException ex = null;
1334 ObjectInputFilter.Status status = null;
1335
1336 if (serialFilter != null) {
1337 try {
1338 status = serialFilter.checkInput(new FilterValues(clazz, arrayLength,
1339 totalObjectRefs, depth, bytesRead));
1340 } catch (RuntimeException e) {
1341 // Preventive interception of an exception to log
1342 status = ObjectInputFilter.Status.REJECTED;
1343 ex = e;
1344 }
1345 if (Logging.filterLogger != null) {
1346 // Debug logging of filter checks that fail; Tracing for those that succeed
1347 Logging.filterLogger.log(status == null || status == ObjectInputFilter.Status.REJECTED
1348 ? Logger.Level.DEBUG
1349 : Logger.Level.TRACE,
1350 "ObjectInputFilter {0}: {1}, array length: {2}, nRefs: {3}, depth: {4}, bytes: {5}, ex: {6}",
1351 status, clazz, arrayLength, totalObjectRefs, depth, bytesRead,
1352 Objects.toString(ex, "n/a"));
1353 }
1354 }
1355 DeserializationEvent event = new DeserializationEvent();
1356 if (event.shouldCommit()) {
1357 event.filterConfigured = serialFilter != null;
1358 event.filterStatus = status != null ? status.name() : null;
1359 event.type = clazz;
1360 event.arrayLength = arrayLength;
1361 event.objectReferences = totalObjectRefs;
1362 event.depth = depth;
1363 event.bytesRead = bytesRead;
1364 event.exceptionType = ex != null ? ex.getClass() : null;
1365 event.exceptionMessage = ex != null ? ex.getMessage() : null;
1366 event.commit();
1367 }
1368 if (serialFilter != null && (status == null || status == ObjectInputFilter.Status.REJECTED)) {
1369 throw new InvalidClassException("filter status: " + status, ex);
1370 }
1371 }
1372
1373 /**
1374 * Checks the given array type and length to ensure that creation of such
1375 * an array is permitted by this ObjectInputStream. The arrayType argument
1376 * must represent an actual array type.
1377 *
1378 * This private method is called via SharedSecrets.
1379 *
1380 * @param arrayType the array type
1381 * @param arrayLength the array length
1382 * @throws NullPointerException if arrayType is null
1383 * @throws IllegalArgumentException if arrayType isn't actually an array type
1384 * @throws StreamCorruptedException if arrayLength is negative
1385 * @throws InvalidClassException if the filter rejects creation
1386 */
1387 private void checkArray(Class<?> arrayType, int arrayLength) throws ObjectStreamException {
1388 if (! arrayType.isArray()) {
1389 throw new IllegalArgumentException("not an array type");
1390 }
1391
1392 if (arrayLength < 0) {
1393 throw new StreamCorruptedException("Array length is negative");
1394 }
1395
1396 filterCheck(arrayType, arrayLength);
1397 }
1398
1399 /**
1400 * Provide access to the persistent fields read from the input stream.
1401 */
1402 public abstract static class GetField {
1403 /**
1404 * Constructor for subclasses to call.
1405 */
1406 public GetField() {}
1407
1408 /**
1409 * Get the ObjectStreamClass that describes the fields in the stream.
1410 *
1411 * @return the descriptor class that describes the serializable fields
1412 */
1413 public abstract ObjectStreamClass getObjectStreamClass();
1414
1415 /**
1416 * Return true if the named field is defaulted and has no value in this
1417 * stream.
1418 *
1419 * @param name the name of the field
1420 * @return true, if and only if the named field is defaulted
1421 * @throws IOException if there are I/O errors while reading from
1422 * the underlying {@code InputStream}
1423 * @throws IllegalArgumentException if {@code name} does not
1424 * correspond to a serializable field
1425 */
1426 public abstract boolean defaulted(String name) throws IOException;
1427
1428 /**
1429 * Get the value of the named boolean field from the persistent field.
1430 *
1431 * @param name the name of the field
1432 * @param val the default value to use if {@code name} does not
1433 * have a value
1434 * @return the value of the named {@code boolean} field
1435 * @throws IOException if there are I/O errors while reading from the
1436 * underlying {@code InputStream}
1437 * @throws IllegalArgumentException if type of {@code name} is
1438 * not serializable or if the field type is incorrect
1439 */
1440 public abstract boolean get(String name, boolean val)
1441 throws IOException;
1442
1443 /**
1444 * Get the value of the named byte field from the persistent field.
1445 *
1446 * @param name the name of the field
1447 * @param val the default value to use if {@code name} does not
1448 * have a value
1449 * @return the value of the named {@code byte} field
1450 * @throws IOException if there are I/O errors while reading from the
1451 * underlying {@code InputStream}
1452 * @throws IllegalArgumentException if type of {@code name} is
1453 * not serializable or if the field type is incorrect
1454 */
1455 public abstract byte get(String name, byte val) throws IOException;
1456
1457 /**
1458 * Get the value of the named char field from the persistent field.
1459 *
1460 * @param name the name of the field
1461 * @param val the default value to use if {@code name} does not
1462 * have a value
1463 * @return the value of the named {@code char} field
1464 * @throws IOException if there are I/O errors while reading from the
1465 * underlying {@code InputStream}
1466 * @throws IllegalArgumentException if type of {@code name} is
1467 * not serializable or if the field type is incorrect
1468 */
1469 public abstract char get(String name, char val) throws IOException;
1470
1471 /**
1472 * Get the value of the named short field from the persistent field.
1473 *
1474 * @param name the name of the field
1475 * @param val the default value to use if {@code name} does not
1476 * have a value
1477 * @return the value of the named {@code short} field
1478 * @throws IOException if there are I/O errors while reading from the
1479 * underlying {@code InputStream}
1480 * @throws IllegalArgumentException if type of {@code name} is
1481 * not serializable or if the field type is incorrect
1482 */
1483 public abstract short get(String name, short val) throws IOException;
1484
1485 /**
1486 * Get the value of the named int field from the persistent field.
1487 *
1488 * @param name the name of the field
1489 * @param val the default value to use if {@code name} does not
1490 * have a value
1491 * @return the value of the named {@code int} field
1492 * @throws IOException if there are I/O errors while reading from the
1493 * underlying {@code InputStream}
1494 * @throws IllegalArgumentException if type of {@code name} is
1495 * not serializable or if the field type is incorrect
1496 */
1497 public abstract int get(String name, int val) throws IOException;
1498
1499 /**
1500 * Get the value of the named long field from the persistent field.
1501 *
1502 * @param name the name of the field
1503 * @param val the default value to use if {@code name} does not
1504 * have a value
1505 * @return the value of the named {@code long} field
1506 * @throws IOException if there are I/O errors while reading from the
1507 * underlying {@code InputStream}
1508 * @throws IllegalArgumentException if type of {@code name} is
1509 * not serializable or if the field type is incorrect
1510 */
1511 public abstract long get(String name, long val) throws IOException;
1512
1513 /**
1514 * Get the value of the named float field from the persistent field.
1515 *
1516 * @param name the name of the field
1517 * @param val the default value to use if {@code name} does not
1518 * have a value
1519 * @return the value of the named {@code float} field
1520 * @throws IOException if there are I/O errors while reading from the
1521 * underlying {@code InputStream}
1522 * @throws IllegalArgumentException if type of {@code name} is
1523 * not serializable or if the field type is incorrect
1524 */
1525 public abstract float get(String name, float val) throws IOException;
1526
1527 /**
1528 * Get the value of the named double field from the persistent field.
1529 *
1530 * @param name the name of the field
1531 * @param val the default value to use if {@code name} does not
1532 * have a value
1533 * @return the value of the named {@code double} field
1534 * @throws IOException if there are I/O errors while reading from the
1535 * underlying {@code InputStream}
1536 * @throws IllegalArgumentException if type of {@code name} is
1537 * not serializable or if the field type is incorrect
1538 */
1539 public abstract double get(String name, double val) throws IOException;
1540
1541 /**
1542 * Get the value of the named Object field from the persistent field.
1543 *
1544 * @param name the name of the field
1545 * @param val the default value to use if {@code name} does not
1546 * have a value
1547 * @return the value of the named {@code Object} field
1548 * @throws ClassNotFoundException Class of a serialized object cannot be found.
1549 * @throws IOException if there are I/O errors while reading from the
1550 * underlying {@code InputStream}
1551 * @throws IllegalArgumentException if type of {@code name} is
1552 * not serializable or if the field type is incorrect
1553 */
1554 public abstract Object get(String name, Object val) throws IOException, ClassNotFoundException;
1555 }
1556
1557 /**
1558 * Clears internal data structures.
1559 */
1560 private void clear() {
1561 handles.clear();
1562 vlist.clear();
1563 }
1564
1565 /**
1566 * Underlying readObject implementation.
1567 * @param type a type expected to be deserialized; non-null
1568 * @param unshared true if the object can not be a reference to a shared object, otherwise false
1569 */
1570 private Object readObject0(Class<?> type, boolean unshared) throws IOException {
1571 boolean oldMode = bin.getBlockDataMode();
1572 if (oldMode) {
1573 int remain = bin.currentBlockRemaining();
1574 if (remain > 0) {
1575 throw new OptionalDataException(remain);
1576 } else if (defaultDataEnd) {
1577 /*
1578 * Fix for 4360508: stream is currently at the end of a field
1579 * value block written via default serialization; since there
1580 * is no terminating TC_ENDBLOCKDATA tag, simulate
1581 * end-of-custom-data behavior explicitly.
1582 */
1583 throw new OptionalDataException(true);
1584 }
1585 bin.setBlockDataMode(false);
1586 }
1587
1588 byte tc;
1589 while ((tc = bin.peekByte()) == TC_RESET) {
1590 bin.readByte();
1591 handleReset();
1592 }
1593
1594 depth++;
1595 totalObjectRefs++;
1596 try {
1597 switch (tc) {
1598 case TC_NULL:
1599 return readNull();
1600
1601 case TC_REFERENCE:
1602 // check the type of the existing object
1603 return type.cast(readHandle(unshared));
1604
1605 case TC_CLASS:
1606 if (type == String.class) {
1607 throw new ClassCastException("Cannot cast a class to java.lang.String");
1608 }
1609 return readClass(unshared);
1610
1611 case TC_CLASSDESC:
1612 case TC_PROXYCLASSDESC:
1613 if (type == String.class) {
1614 throw new ClassCastException("Cannot cast a class to java.lang.String");
1615 }
1616 return readClassDesc(unshared);
1617
1618 case TC_STRING:
1619 case TC_LONGSTRING:
1620 return checkResolve(readString(unshared));
1621
1622 case TC_ARRAY:
1623 if (type == String.class) {
1624 throw new ClassCastException("Cannot cast an array to java.lang.String");
1625 }
1626 return checkResolve(readArray(unshared));
1627
1628 case TC_ENUM:
1629 if (type == String.class) {
1630 throw new ClassCastException("Cannot cast an enum to java.lang.String");
1631 }
1632 return checkResolve(readEnum(unshared));
1633
1634 case TC_OBJECT:
1635 if (type == String.class) {
1636 throw new ClassCastException("Cannot cast an object to java.lang.String");
1637 }
1638 return checkResolve(readOrdinaryObject(unshared));
1639
1640 case TC_EXCEPTION:
1641 if (type == String.class) {
1642 throw new ClassCastException("Cannot cast an exception to java.lang.String");
1643 }
1644 IOException ex = readFatalException();
1645 throw new WriteAbortedException("writing aborted", ex);
1646
1647 case TC_BLOCKDATA:
1648 case TC_BLOCKDATALONG:
1649 if (oldMode) {
1650 bin.setBlockDataMode(true);
1651 bin.peek(); // force header read
1652 throw new OptionalDataException(
1653 bin.currentBlockRemaining());
1654 } else {
1655 throw new StreamCorruptedException(
1656 "unexpected block data");
1657 }
1658
1659 case TC_ENDBLOCKDATA:
1660 if (oldMode) {
1661 throw new OptionalDataException(true);
1662 } else {
1663 throw new StreamCorruptedException(
1664 "unexpected end of block data");
1665 }
1666
1667 default:
1668 throw new StreamCorruptedException(
1669 String.format("invalid type code: %02X", tc));
1670 }
1671 } finally {
1672 depth--;
1673 bin.setBlockDataMode(oldMode);
1674 }
1675 }
1676
1677 /**
1678 * If resolveObject has been enabled and given object does not have an
1679 * exception associated with it, calls resolveObject to determine
1680 * replacement for object, and updates handle table accordingly. Returns
1681 * replacement object, or echoes provided object if no replacement
1682 * occurred. Expects that passHandle is set to given object's handle prior
1683 * to calling this method.
1684 */
1685 private Object checkResolve(Object obj) throws IOException {
1686 if (!enableResolve || handles.lookupException(passHandle) != null) {
1687 return obj;
1688 }
1689 Object rep = resolveObject(obj);
1690 if (rep != obj) {
1691 // The type of the original object has been filtered but resolveObject
1692 // may have replaced it; filter the replacement's type
1693 if (rep != null) {
1694 if (rep.getClass().isArray()) {
1695 filterCheck(rep.getClass(), Array.getLength(rep));
1696 } else {
1697 filterCheck(rep.getClass(), -1);
1698 }
1699 }
1700 handles.setObject(passHandle, rep);
1701 }
1702 return rep;
1703 }
1704
1705 /**
1706 * Reads string without allowing it to be replaced in stream. Called from
1707 * within ObjectStreamClass.read().
1708 */
1709 String readTypeString() throws IOException {
1710 int oldHandle = passHandle;
1711 try {
1712 byte tc = bin.peekByte();
1713 return switch (tc) {
1714 case TC_NULL -> (String) readNull();
1715 case TC_REFERENCE -> (String) readHandle(false);
1716 case TC_STRING, TC_LONGSTRING -> readString(false);
1717 default -> throw new StreamCorruptedException(
1718 String.format("invalid type code: %02X", tc));
1719 };
1720 } finally {
1721 passHandle = oldHandle;
1722 }
1723 }
1724
1725 /**
1726 * Reads in null code, sets passHandle to NULL_HANDLE and returns null.
1727 */
1728 private Object readNull() throws IOException {
1729 if (bin.readByte() != TC_NULL) {
1730 throw new InternalError();
1731 }
1732 passHandle = NULL_HANDLE;
1733 return null;
1734 }
1735
1736 /**
1737 * Reads in object handle, sets passHandle to the read handle, and returns
1738 * object associated with the handle.
1739 */
1740 private Object readHandle(boolean unshared) throws IOException {
1741 if (bin.readByte() != TC_REFERENCE) {
1742 throw new InternalError();
1743 }
1744 passHandle = bin.readInt() - baseWireHandle;
1745 if (passHandle < 0 || passHandle >= handles.size()) {
1746 throw new StreamCorruptedException(
1747 String.format("invalid handle value: %08X", passHandle +
1748 baseWireHandle));
1749 }
1750 if (unshared) {
1751 // REMIND: what type of exception to throw here?
1752 throw new InvalidObjectException(
1753 "cannot read back reference as unshared");
1754 }
1755
1756 Object obj = handles.lookupObject(passHandle);
1757 if (obj == unsharedMarker) {
1758 // REMIND: what type of exception to throw here?
1759 throw new InvalidObjectException(
1760 "cannot read back reference to unshared object");
1761 }
1762 filterCheck(null, -1); // just a check for number of references, depth, no class
1763 return obj;
1764 }
1765
1766 /**
1767 * Reads in and returns class object. Sets passHandle to class object's
1768 * assigned handle. Returns null if class is unresolvable (in which case a
1769 * ClassNotFoundException will be associated with the class' handle in the
1770 * handle table).
1771 */
1772 private Class<?> readClass(boolean unshared) throws IOException {
1773 if (bin.readByte() != TC_CLASS) {
1774 throw new InternalError();
1775 }
1776 ObjectStreamClass desc = readClassDesc(false);
1777 Class<?> cl = desc.forClass();
1778 passHandle = handles.assign(unshared ? unsharedMarker : cl);
1779
1780 ClassNotFoundException resolveEx = desc.getResolveException();
1781 if (resolveEx != null) {
1782 handles.markException(passHandle, resolveEx);
1783 }
1784
1785 handles.finish(passHandle);
1786 return cl;
1787 }
1788
1789 /**
1790 * Reads in and returns (possibly null) class descriptor. Sets passHandle
1791 * to class descriptor's assigned handle. If class descriptor cannot be
1792 * resolved to a class in the local VM, a ClassNotFoundException is
1793 * associated with the class descriptor's handle.
1794 */
1795 private ObjectStreamClass readClassDesc(boolean unshared)
1796 throws IOException
1797 {
1798 byte tc = bin.peekByte();
1799
1800 return switch (tc) {
1801 case TC_NULL -> (ObjectStreamClass) readNull();
1802 case TC_PROXYCLASSDESC -> readProxyDesc(unshared);
1803 case TC_CLASSDESC -> readNonProxyDesc(unshared);
1804 case TC_REFERENCE -> {
1805 var d = (ObjectStreamClass) readHandle(unshared);
1806 // Should only reference initialized class descriptors
1807 d.checkInitialized();
1808 yield d;
1809 }
1810 default -> throw new StreamCorruptedException(
1811 String.format("invalid type code: %02X", tc));
1812 };
1813 }
1814
1815 /**
1816 * Reads in and returns class descriptor for a dynamic proxy class. Sets
1817 * passHandle to proxy class descriptor's assigned handle. If proxy class
1818 * descriptor cannot be resolved to a class in the local VM, a
1819 * ClassNotFoundException is associated with the descriptor's handle.
1820 */
1821 private ObjectStreamClass readProxyDesc(boolean unshared)
1822 throws IOException
1823 {
1824 if (bin.readByte() != TC_PROXYCLASSDESC) {
1825 throw new InternalError();
1826 }
1827
1828 ObjectStreamClass desc = new ObjectStreamClass();
1829 int descHandle = handles.assign(unshared ? unsharedMarker : desc);
1830 passHandle = NULL_HANDLE;
1831
1832 int numIfaces = bin.readInt();
1833 if (numIfaces > 65535) {
1834 // Report specification limit exceeded
1835 throw new InvalidObjectException("interface limit exceeded: " +
1836 numIfaces +
1837 ", limit: " + Caches.PROXY_INTERFACE_LIMIT);
1838 }
1839 String[] ifaces = new String[numIfaces];
1840 for (int i = 0; i < numIfaces; i++) {
1841 ifaces[i] = bin.readUTF();
1842 }
1843
1844 // Recheck against implementation limit and throw with interface names
1845 if (numIfaces > Caches.PROXY_INTERFACE_LIMIT) {
1846 throw new InvalidObjectException("interface limit exceeded: " +
1847 numIfaces +
1848 ", limit: " + Caches.PROXY_INTERFACE_LIMIT +
1849 "; " + Arrays.toString(ifaces));
1850 }
1851 Class<?> cl = null;
1852 ClassNotFoundException resolveEx = null;
1853 bin.setBlockDataMode(true);
1854 try {
1855 if ((cl = resolveProxyClass(ifaces)) == null) {
1856 resolveEx = new ClassNotFoundException("null class");
1857 } else if (!Proxy.isProxyClass(cl)) {
1858 throw new InvalidClassException("Not a proxy");
1859 } else {
1860 // Filter the interfaces
1861 for (Class<?> clazz : cl.getInterfaces()) {
1862 filterCheck(clazz, -1);
1863 }
1864 }
1865 } catch (ClassNotFoundException ex) {
1866 resolveEx = ex;
1867 } catch (IllegalAccessError aie) {
1868 throw new InvalidClassException(aie.getMessage(), aie);
1869 } catch (OutOfMemoryError oome) {
1870 throw genInvalidObjectException(oome, ifaces);
1871 }
1872
1873 // Call filterCheck on the class before reading anything else
1874 filterCheck(cl, -1);
1875
1876 skipCustomData();
1877
1878 try {
1879 totalObjectRefs++;
1880 depth++;
1881 desc.initProxy(cl, resolveEx, readClassDesc(false));
1882 } catch (OutOfMemoryError oome) {
1883 throw genInvalidObjectException(oome, ifaces);
1884 } finally {
1885 depth--;
1886 }
1887
1888 handles.finish(descHandle);
1889 passHandle = descHandle;
1890 return desc;
1891 }
1892
1893 // Generate an InvalidObjectException for an OutOfMemoryError
1894 // Use String.concat() to avoid string formatting invoke dynamic
1895 private static InvalidObjectException genInvalidObjectException(OutOfMemoryError oome,
1896 String[] ifaces) {
1897 return new InvalidObjectException("Proxy interface limit exceeded: "
1898 .concat(Arrays.toString(ifaces)), oome);
1899 }
1900
1901 /**
1902 * Reads in and returns class descriptor for a class that is not a dynamic
1903 * proxy class. Sets passHandle to class descriptor's assigned handle. If
1904 * class descriptor cannot be resolved to a class in the local VM, a
1905 * ClassNotFoundException is associated with the descriptor's handle.
1906 */
1907 private ObjectStreamClass readNonProxyDesc(boolean unshared)
1908 throws IOException
1909 {
1910 if (bin.readByte() != TC_CLASSDESC) {
1911 throw new InternalError();
1912 }
1913
1914 ObjectStreamClass desc = new ObjectStreamClass();
1915 int descHandle = handles.assign(unshared ? unsharedMarker : desc);
1916 passHandle = NULL_HANDLE;
1917
1918 ObjectStreamClass readDesc;
1919 try {
1920 readDesc = readClassDescriptor();
1921 } catch (ClassNotFoundException ex) {
1922 throw new InvalidClassException("failed to read class descriptor",
1923 ex);
1924 }
1925
1926 Class<?> cl = null;
1927 ClassNotFoundException resolveEx = null;
1928 bin.setBlockDataMode(true);
1929 try {
1930 if ((cl = resolveClass(readDesc)) == null) {
1931 resolveEx = new ClassNotFoundException("null class");
1932 }
1933 } catch (ClassNotFoundException ex) {
1934 resolveEx = ex;
1935 }
1936
1937 // Call filterCheck on the class before reading anything else
1938 filterCheck(cl, -1);
1939
1940 skipCustomData();
1941
1942 try {
1943 totalObjectRefs++;
1944 depth++;
1945 desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));
1946
1947 if (cl != null) {
1948 // Check that serial filtering has been done on the local class descriptor's superclass,
1949 // in case it does not appear in the stream.
1950
1951 // Find the next super descriptor that has a local class descriptor.
1952 // Descriptors for which there is no local class are ignored.
1953 ObjectStreamClass superLocal = null;
1954 for (ObjectStreamClass sDesc = desc.getSuperDesc(); sDesc != null; sDesc = sDesc.getSuperDesc()) {
1955 if ((superLocal = sDesc.getLocalDesc()) != null) {
1956 break;
1957 }
1958 }
1959
1960 // Scan local descriptor superclasses for a match with the local descriptor of the super found above.
1961 // For each super descriptor before the match, invoke the serial filter on the class.
1962 // The filter is invoked for each class that has not already been filtered
1963 // but would be filtered if the instance had been serialized by this Java runtime.
1964 for (ObjectStreamClass lDesc = desc.getLocalDesc().getSuperDesc();
1965 lDesc != null && lDesc != superLocal;
1966 lDesc = lDesc.getSuperDesc()) {
1967 filterCheck(lDesc.forClass(), -1);
1968 }
1969 }
1970 } finally {
1971 depth--;
1972 }
1973
1974 handles.finish(descHandle);
1975 passHandle = descHandle;
1976
1977 return desc;
1978 }
1979
1980 /**
1981 * Reads in and returns new string. Sets passHandle to new string's
1982 * assigned handle.
1983 */
1984 private String readString(boolean unshared) throws IOException {
1985 byte tc = bin.readByte();
1986 String str = switch (tc) {
1987 case TC_STRING -> bin.readUTF();
1988 case TC_LONGSTRING -> bin.readLongUTF();
1989 default -> throw new StreamCorruptedException(
1990 String.format("invalid type code: %02X", tc));
1991 };
1992 passHandle = handles.assign(unshared ? unsharedMarker : str);
1993 handles.finish(passHandle);
1994 return str;
1995 }
1996
1997 /**
1998 * Reads in and returns array object, or null if array class is
1999 * unresolvable. Sets passHandle to array's assigned handle.
2000 */
2001 private Object readArray(boolean unshared) throws IOException {
2002 if (bin.readByte() != TC_ARRAY) {
2003 throw new InternalError();
2004 }
2005
2006 ObjectStreamClass desc = readClassDesc(false);
2007 int len = bin.readInt();
2008 if (len < 0) {
2009 throw new StreamCorruptedException("Array length is negative");
2010 }
2011 filterCheck(desc.forClass(), len);
2012
2013 Object array = null;
2014 Class<?> cl, ccl = null;
2015 if ((cl = desc.forClass()) != null) {
2016 ccl = cl.getComponentType();
2017 array = Array.newInstance(ccl, len);
2018 }
2019
2020 int arrayHandle = handles.assign(unshared ? unsharedMarker : array);
2021 ClassNotFoundException resolveEx = desc.getResolveException();
2022 if (resolveEx != null) {
2023 handles.markException(arrayHandle, resolveEx);
2024 }
2025
2026 if (ccl == null) {
2027 for (int i = 0; i < len; i++) {
2028 readObject0(Object.class, false);
2029 }
2030 } else if (ccl.isPrimitive()) {
2031 if (ccl == Integer.TYPE) {
2032 bin.readInts((int[]) array, 0, len);
2033 } else if (ccl == Byte.TYPE) {
2034 bin.readFully((byte[]) array, 0, len, true);
2035 } else if (ccl == Long.TYPE) {
2036 bin.readLongs((long[]) array, 0, len);
2037 } else if (ccl == Float.TYPE) {
2038 bin.readFloats((float[]) array, 0, len);
2039 } else if (ccl == Double.TYPE) {
2040 bin.readDoubles((double[]) array, 0, len);
2041 } else if (ccl == Short.TYPE) {
2042 bin.readShorts((short[]) array, 0, len);
2043 } else if (ccl == Character.TYPE) {
2044 bin.readChars((char[]) array, 0, len);
2045 } else if (ccl == Boolean.TYPE) {
2046 bin.readBooleans((boolean[]) array, 0, len);
2047 } else {
2048 throw new InternalError();
2049 }
2050 } else {
2051 Object[] oa = (Object[]) array;
2052 for (int i = 0; i < len; i++) {
2053 oa[i] = readObject0(Object.class, false);
2054 handles.markDependency(arrayHandle, passHandle);
2055 }
2056 }
2057
2058 handles.finish(arrayHandle);
2059 passHandle = arrayHandle;
2060 return array;
2061 }
2062
2063 /**
2064 * Reads in and returns enum constant, or null if enum type is
2065 * unresolvable. Sets passHandle to enum constant's assigned handle.
2066 */
2067 private Enum<?> readEnum(boolean unshared) throws IOException {
2068 if (bin.readByte() != TC_ENUM) {
2069 throw new InternalError();
2070 }
2071
2072 ObjectStreamClass desc = readClassDesc(false);
2073 if (!desc.isEnum()) {
2074 throw new InvalidClassException("non-enum class: " + desc);
2075 }
2076
2077 int enumHandle = handles.assign(unshared ? unsharedMarker : null);
2078 ClassNotFoundException resolveEx = desc.getResolveException();
2079 if (resolveEx != null) {
2080 handles.markException(enumHandle, resolveEx);
2081 }
2082
2083 String name = readString(false);
2084 Enum<?> result = null;
2085 Class<?> cl = desc.forClass();
2086 if (cl != null) {
2087 try {
2088 @SuppressWarnings("unchecked")
2089 Enum<?> en = Enum.valueOf((Class)cl, name);
2090 result = en;
2091 } catch (IllegalArgumentException ex) {
2092 throw new InvalidObjectException("enum constant " +
2093 name + " does not exist in " + cl, ex);
2094 }
2095 if (!unshared) {
2096 handles.setObject(enumHandle, result);
2097 }
2098 }
2099
2100 handles.finish(enumHandle);
2101 passHandle = enumHandle;
2102 return result;
2103 }
2104
2105 /**
2106 * Reads and returns "ordinary" (i.e., not a String, Class,
2107 * ObjectStreamClass, array, or enum constant) object, or null if object's
2108 * class is unresolvable (in which case a ClassNotFoundException will be
2109 * associated with object's handle). Sets passHandle to object's assigned
2110 * handle.
2111 */
2112 private Object readOrdinaryObject(boolean unshared)
2113 throws IOException
2114 {
2115 if (bin.readByte() != TC_OBJECT) {
2116 throw new InternalError();
2117 }
2118
2119 ObjectStreamClass desc = readClassDesc(false);
2120 desc.checkDeserialize();
2121
2122 Class<?> cl = desc.forClass();
2123 if (cl == String.class || cl == Class.class
2124 || cl == ObjectStreamClass.class) {
2125 throw new InvalidClassException("invalid class descriptor");
2126 }
2127
2128 // Assign the handle and initially set to null or the unsharedMarker
2129 passHandle = handles.assign(unshared ? unsharedMarker : null);
2130 ClassNotFoundException resolveEx = desc.getResolveException();
2131 if (resolveEx != null) {
2132 handles.markException(passHandle, resolveEx);
2133 }
2134
2135 try {
2136 // Dispatch on the factory mode to read an object from the stream.
2137 Object obj = switch (desc.factoryMode()) {
2138 case READ_OBJECT_DEFAULT -> readSerialDefaultObject(desc, unshared);
2139 case READ_OBJECT_CUSTOM -> readSerialCustomData(desc, unshared);
2140 case READ_RECORD -> readRecord(desc, unshared);
2141 case READ_EXTERNALIZABLE -> readExternalObject(desc, unshared);
2142 case READ_OBJECT_VALUE -> readObjectValue(desc, unshared);
2143 case READ_NO_LOCAL_CLASS -> readAbsentLocalClass(desc, unshared);
2144 case null -> throw new AssertionError("Unknown factoryMode for: " + desc.getName(),
2145 resolveEx);
2146 };
2147
2148 handles.finish(passHandle);
2149
2150 if (obj != null &&
2151 handles.lookupException(passHandle) == null &&
2152 desc.hasReadResolveMethod())
2153 {
2154 Object rep = desc.invokeReadResolve(obj);
2155 if (unshared && rep.getClass().isArray()) {
2156 rep = cloneArray(rep);
2157 }
2158 if (rep != obj) {
2159 // Filter the replacement object
2160 if (rep != null) {
2161 if (rep.getClass().isArray()) {
2162 filterCheck(rep.getClass(), Array.getLength(rep));
2163 } else {
2164 filterCheck(rep.getClass(), -1);
2165 }
2166 }
2167 handles.setObject(passHandle, obj = rep);
2168 }
2169 }
2170
2171 return obj;
2172 } catch (UncheckedIOException uioe) {
2173 // Consistent re-throw for nested UncheckedIOExceptions
2174 throw uioe.getCause();
2175 }
2176 }
2177
2178 /**
2179 * {@return a value class instance by invoking its constructor with field values read from the stream.
2180 * The fields of the class in the stream are matched to the local fields and applied to
2181 * the constructor.
2182 * If the stream contains superclasses with serializable fields,
2183 * an InvalidClassException is thrown with an incompatible class change message.
2184 *
2185 * @param desc the class descriptor read from the stream, the local class is a value class
2186 * @param unshared if the object is not to be shared
2187 * @throws InvalidClassException if the stream contains a superclass with serializable fields.
2188 * @throws IOException if there are I/O errors while reading from the
2189 * underlying {@code InputStream}
2190 */
2191 private Object readObjectValue(ObjectStreamClass desc, boolean unshared) throws IOException {
2192 final ObjectStreamClass localDesc = desc.getLocalDesc();
2193 // Check for un-expected fields in superclasses
2194 List<ClassDataSlot> slots = desc.getClassDataLayout();
2195 for (int i = 0; i < slots.size()-1; i++) {
2196 ClassDataSlot slot = slots.get(i);
2197 if (slot.hasData && slot.desc.getFields(false).length > 0) {
2198 throw new InvalidClassException("incompatible class change to value class: " +
2199 "stream class has non-empty super type: " + desc.getName());
2200 }
2201 }
2202 // Read values for the value class fields
2203 FieldValues fieldValues = new FieldValues(desc, true);
2204
2205 // Get value object constructor adapted to take primitive value buffer and object array.
2206 MethodHandle consMH = ConstructorSupport.deserializationValueCons(desc);
2207 try {
2208 Object obj = (Object) consMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
2209 if (!unshared)
2210 handles.setObject(passHandle, obj);
2211 return obj;
2212 } catch (Exception e) {
2213 throw new InvalidObjectException(e.getMessage(), e);
2214 } catch (Error e) {
2215 throw e;
2216 } catch (Throwable t) {
2217 throw new InvalidObjectException("ReflectiveOperationException " +
2218 "during deserialization", t);
2219 }
2220 }
2221
2222 /**
2223 * Creates a new object and invokes its readExternal method to read its contents.
2224 *
2225 * If the class is instantiable, read externalizable data by invoking readExternal()
2226 * method of obj; otherwise, attempts to skip over externalizable data.
2227 * Expects that passHandle is set to obj's handle before this method is
2228 * called. The new object is entered in the handle table immediately,
2229 * allowing it to leak before it is completely read.
2230 */
2231 private Object readExternalObject(ObjectStreamClass desc, boolean unshared)
2232 throws IOException
2233 {
2234 // For Externalizable objects,
2235 // create the instance, publish the ref, and read the data
2236 Externalizable obj = null;
2237 try {
2238 if (desc.isInstantiable()) {
2239 obj = (Externalizable) desc.newInstance();
2240 }
2241 } catch (Exception ex) {
2242 throw new InvalidClassException(desc.getName(),
2243 "unable to create instance", ex);
2244 }
2245
2246 if (!unshared)
2247 handles.setObject(passHandle, obj);
2248
2249 SerialCallbackContext oldContext = curContext;
2250 if (oldContext != null)
2251 oldContext.check();
2252 curContext = null;
2253 try {
2254 boolean blocked = desc.hasBlockExternalData();
2255 if (blocked) {
2256 bin.setBlockDataMode(true);
2257 }
2258 if (obj != null) {
2259 try {
2260 obj.readExternal(this);
2261 } catch (ClassNotFoundException ex) {
2262 /*
2263 * In most cases, the handle table has already propagated
2264 * a CNFException to passHandle at this point; this mark
2265 * call is included to address cases where the readExternal
2266 * method has cons'ed and thrown a new CNFException of its
2267 * own.
2268 */
2269 handles.markException(passHandle, ex);
2270 }
2271 }
2272 if (blocked) {
2273 skipCustomData();
2274 }
2275 } finally {
2276 if (oldContext != null)
2277 oldContext.check();
2278 curContext = oldContext;
2279 }
2280 /*
2281 * At this point, if the externalizable data was not written in
2282 * block-data form and either the externalizable class doesn't exist
2283 * locally (i.e., obj == null) or readExternal() just threw a
2284 * CNFException, then the stream is probably in an inconsistent state,
2285 * since some (or all) of the externalizable data may not have been
2286 * consumed. Since there's no "correct" action to take in this case,
2287 * we mimic the behavior of past serialization implementations and
2288 * blindly hope that the stream is in sync; if it isn't and additional
2289 * externalizable data remains in the stream, a subsequent read will
2290 * most likely throw a StreamCorruptedException.
2291 */
2292 return obj;
2293 }
2294
2295 /**
2296 * Reads and returns a record.
2297 * If an exception is marked for any of the fields, the dependency
2298 * mechanism marks the record as having an exception.
2299 * Null is returned from readRecord and later the exception is thrown at
2300 * the exit of {@link #readObject(Class)}.
2301 */
2302 private Object readRecord(ObjectStreamClass desc, boolean unshared) throws IOException {
2303 List<ClassDataSlot> slots = desc.getClassDataLayout();
2304 if (slots.size() != 1) {
2305 // skip any superclass stream field values
2306 for (int i = 0; i < slots.size()-1; i++) {
2307 if (slots.get(i).hasData) {
2308 new FieldValues(slots.get(i).desc, true);
2309 }
2310 }
2311 }
2312
2313 FieldValues fieldValues = new FieldValues(desc, true);
2314 if (handles.lookupException(passHandle) != null) {
2315 return null; // slot marked with exception, don't create record
2316 }
2317
2318 // get canonical record constructor adapted to take two arguments:
2319 // - byte[] primValues
2320 // - Object[] objValues
2321 // and return Object
2322 MethodHandle ctrMH = ConstructorSupport.deserializationCtr(desc);
2323
2324 try {
2325 Object obj = (Object) ctrMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
2326 if (!unshared)
2327 handles.setObject(passHandle, obj);
2328 return obj;
2329 } catch (Exception e) {
2330 throw new InvalidObjectException(e.getMessage(), e);
2331 } catch (Error e) {
2332 throw e;
2333 } catch (Throwable t) {
2334 throw new InvalidObjectException("ReflectiveOperationException " +
2335 "during deserialization", t);
2336 }
2337 }
2338
2339 /**
2340 * Construct an object from the stream for a class that has only default read object behaviors.
2341 * For each object, the fields are read before any are assigned.
2342 * The new instance is entered in the handle table if it is unshared,
2343 * allowing it to escape before it is initialized.
2344 * The `readObject` and `readObjectNoData` methods are not present and are not called.
2345 *
2346 * @param desc the class descriptor
2347 * @param unshared true if the object should be shared
2348 * @return the object constructed from the stream data
2349 * @throws IOException if there are I/O errors while reading from the
2350 * underlying {@code InputStream}
2351 * @throws InvalidClassException if the instance creation fails
2352 */
2353 private Object readSerialDefaultObject(ObjectStreamClass desc, boolean unshared)
2354 throws IOException, InvalidClassException {
2355 if (!desc.isInstantiable()) {
2356 // No local class to create, read and discard
2357 return readAbsentLocalClass(desc, unshared);
2358 }
2359 try {
2360 final Object obj = desc.newInstance();
2361 if (!unshared)
2362 handles.setObject(passHandle, obj);
2363
2364 // Best effort Failure Atomicity; slotValues will be non-null if field
2365 // values can be set after reading all field data in the hierarchy.
2366 List<ClassDataSlot> slots = desc.getClassDataLayout();
2367 List<FieldValues> slotValues = new ArrayList<>(slots.size());
2368 for (ClassDataSlot s : slots) {
2369 if (s.hasData) {
2370 var value = new FieldValues(s.desc, true);
2371 finishBlockData(s.desc);
2372 slotValues.add(value);
2373 }
2374 }
2375
2376 if (handles.lookupException(passHandle) != null) {
2377 return null; // some exception for a class, do not return the object
2378 }
2379
2380 // Check that the types are assignable for all slots before assigning.
2381 for (FieldValues slotValue : slotValues) {
2382 slotValue.defaultCheckFieldValues(obj);
2383 }
2384 for (FieldValues v : slotValues) {
2385 v.defaultSetFieldValues(obj);
2386 }
2387 return obj;
2388 } catch (InstantiationException | InvocationTargetException ex) {
2389 throw new InvalidClassException(desc.forClass().getName(),
2390 "unable to create instance", ex);
2391 }
2392 }
2393
2394
2395 /**
2396 * Reads (or attempts to skip, if not instantiatable or is tagged with a
2397 * ClassNotFoundException) instance data for each serializable class of
2398 * object in stream, from superclass to subclass.
2399 * Expects that passHandle is set to current handle before this method is called.
2400 */
2401 private Object readSerialCustomData(ObjectStreamClass desc, boolean unshared)
2402 throws IOException
2403 {
2404 if (!desc.isInstantiable()) {
2405 // No local class to create, read and discard
2406 return readAbsentLocalClass(desc, unshared);
2407 }
2408
2409 try {
2410 Object obj = desc.newInstance();
2411 if (!unshared)
2412 handles.setObject(passHandle, obj);
2413 // Read data into each of the slots for the class
2414 return readSerialCustomSlots(obj, desc.getClassDataLayout());
2415 } catch (InstantiationException | InvocationTargetException ex) {
2416 throw new InvalidClassException(desc.forClass().getName(),
2417 "unable to create instance", ex);
2418 }
2419 }
2420
2421 /**
2422 * Reads from the stream using custom or default readObject methods appropriate.
2423 * For each slot, either the custom readObject method or the default reader of fields
2424 * is invoked. Unused slot specific custom data is discarded.
2425 * This function is used by {@link #readSerialCustomData}.
2426 *
2427 * @param obj the object to assign the values to
2428 * @param slots a list of slots to read from the stream
2429 * @return the object being initialized
2430 * @throws IOException if there are I/O errors while reading from the
2431 * underlying {@code InputStream}
2432 */
2433 private Object readSerialCustomSlots(Object obj, List<ClassDataSlot> slots) throws IOException {
2434
2435 for (ClassDataSlot slot : slots) {
2436 ObjectStreamClass slotDesc = slot.desc;
2437 if (slot.hasData) {
2438 if (slotDesc.hasReadObjectMethod() &&
2439 handles.lookupException(passHandle) == null) {
2440 // Invoke slot custom readObject method
2441 readSlotViaReadObject(obj, slotDesc);
2442 } else {
2443 // Read fields of the current descriptor into a new FieldValues
2444 FieldValues values = new FieldValues(slotDesc, true);
2445 if (handles.lookupException(passHandle) == null) {
2446 // Set the instance fields if no previous exception
2447 values.defaultCheckFieldValues(obj);
2448 values.defaultSetFieldValues(obj);
2449 }
2450 finishBlockData(slotDesc);
2451 }
2452 } else {
2453 if (slotDesc.hasReadObjectNoDataMethod() &&
2454 handles.lookupException(passHandle) == null) {
2455 slotDesc.invokeReadObjectNoData(obj);
2456 }
2457 }
2458 }
2459 return obj;
2460 }
2461
2462 /**
2463 * Invoke the readObject method of the class to read and store the state from the stream.
2464 *
2465 * @param obj an instance of the class being created, only partially initialized.
2466 * @param slotDesc the ObjectStreamDescriptor for the current class
2467 * @throws IOException if there are I/O errors while reading from the
2468 * underlying {@code InputStream}
2469 */
2470 private void readSlotViaReadObject(Object obj, ObjectStreamClass slotDesc) throws IOException {
2471 assert obj != null : "readSlotViaReadObject called when obj == null";
2472
2473 SerialCallbackContext oldContext = curContext;
2474 if (oldContext != null)
2475 oldContext.check();
2476 try {
2477 curContext = new SerialCallbackContext(obj, slotDesc);
2478
2479 bin.setBlockDataMode(true);
2480 slotDesc.invokeReadObject(obj, this);
2481 } catch (ClassNotFoundException ex) {
2482 /*
2483 * In most cases, the handle table has already
2484 * propagated a CNFException to passHandle at this
2485 * point; this mark call is included to address cases
2486 * where the custom readObject method has cons'ed and
2487 * thrown a new CNFException of its own.
2488 */
2489 handles.markException(passHandle, ex);
2490 } finally {
2491 curContext.setUsed();
2492 if (oldContext!= null)
2493 oldContext.check();
2494 curContext = oldContext;
2495 }
2496
2497 /*
2498 * defaultDataEnd may have been set indirectly by custom
2499 * readObject() method when calling defaultReadObject() or
2500 * readFields(); clear it to restore normal read behavior.
2501 */
2502 defaultDataEnd = false;
2503
2504 finishBlockData(slotDesc);
2505 }
2506
2507
2508 /**
2509 * Read and discard an entire object, leaving a null reference in the HandleTable.
2510 * The descriptor of the class in the stream is used to read the fields from the stream.
2511 * There is no instance in which to store the field values.
2512 * Custom data following the fields of any slot is read and discarded.
2513 * References to nested objects are read and retained in the
2514 * handle table using the regular mechanism.
2515 * Handles later in the stream may refer to the nested objects.
2516 *
2517 * @param desc the stream class descriptor
2518 * @param unshared the unshared flag, ignored since no object is created
2519 * @return null, no object is created
2520 * @throws IOException if there are I/O errors while reading from the
2521 * underlying {@code InputStream}
2522 */
2523 private Object readAbsentLocalClass(ObjectStreamClass desc, boolean unshared)
2524 throws IOException {
2525 desc.getClassDataLayout().stream()
2526 .filter(s -> s.hasData)
2527 .forEach(s2 -> {new FieldValues(s2.desc, true); finishBlockData(s2.desc);});
2528 return null;
2529 }
2530
2531 // Finish handling of block data by skipping any remaining and setting BlockDataMode = false
2532 private void finishBlockData(ObjectStreamClass slotDesc) throws UncheckedIOException {
2533 try {
2534 if (slotDesc.hasWriteObjectData()) {
2535 skipCustomData();
2536 } else {
2537 bin.setBlockDataMode(false);
2538 }
2539 } catch (IOException ioe) {
2540 throw new UncheckedIOException(ioe);
2541 }
2542 }
2543
2544 /**
2545 * Skips over all block data and objects until TC_ENDBLOCKDATA is
2546 * encountered.
2547 */
2548 private void skipCustomData() throws IOException {
2549 int oldHandle = passHandle;
2550 for (;;) {
2551 if (bin.getBlockDataMode()) {
2552 bin.skipBlockData();
2553 bin.setBlockDataMode(false);
2554 }
2555 switch (bin.peekByte()) {
2556 case TC_BLOCKDATA:
2557 case TC_BLOCKDATALONG:
2558 bin.setBlockDataMode(true);
2559 break;
2560
2561 case TC_ENDBLOCKDATA:
2562 bin.readByte();
2563 passHandle = oldHandle;
2564 return;
2565
2566 default:
2567 readObject0(Object.class, false);
2568 break;
2569 }
2570 }
2571 }
2572
2573 /**
2574 * Reads in and returns IOException that caused serialization to abort.
2575 * All stream state is discarded prior to reading in fatal exception. Sets
2576 * passHandle to fatal exception's handle.
2577 */
2578 private IOException readFatalException() throws IOException {
2579 if (bin.readByte() != TC_EXCEPTION) {
2580 throw new InternalError();
2581 }
2582 clear();
2583 // Check that an object follows the TC_EXCEPTION typecode
2584 byte tc = bin.peekByte();
2585 if (tc != TC_OBJECT &&
2586 tc != TC_REFERENCE) {
2587 throw new StreamCorruptedException(
2588 String.format("invalid type code: %02X", tc));
2589 }
2590 return (IOException) readObject0(Object.class, false);
2591 }
2592
2593 /**
2594 * If recursion depth is 0, clears internal data structures; otherwise,
2595 * throws a StreamCorruptedException. This method is called when a
2596 * TC_RESET typecode is encountered.
2597 */
2598 private void handleReset() throws StreamCorruptedException {
2599 if (depth > 0) {
2600 throw new StreamCorruptedException(
2601 "unexpected reset; recursion depth: " + depth);
2602 }
2603 clear();
2604 }
2605
2606 /**
2607 * Returns the first non-null and non-platform class loader (not counting
2608 * class loaders of generated reflection implementation classes) up the
2609 * execution stack, or the platform class loader if only code from the
2610 * bootstrap and platform class loader is on the stack.
2611 */
2612 private static ClassLoader latestUserDefinedLoader() {
2613 return jdk.internal.misc.VM.latestUserDefinedLoader();
2614 }
2615
2616 /**
2617 * Default GetField implementation.
2618 */
2619 private final class FieldValues extends GetField {
2620
2621 /** class descriptor describing serializable fields */
2622 private final ObjectStreamClass desc;
2623 /** primitive field values */
2624 final byte[] primValues;
2625 /** object field values */
2626 final Object[] objValues;
2627 /** object field value handles */
2628 private final int[] objHandles;
2629
2630 /**
2631 * Creates FieldValues object for reading fields defined in given
2632 * class descriptor.
2633 * @param desc the ObjectStreamClass to read
2634 * @param recordDependencies if true, record the dependencies
2635 * from current PassHandle and the object's read.
2636 * @throws UncheckedIOException if any IOException occurs
2637 */
2638 FieldValues(ObjectStreamClass desc, boolean recordDependencies) throws UncheckedIOException {
2639 try {
2640 this.desc = desc;
2641 int primDataSize = desc.getPrimDataSize();
2642 primValues = (primDataSize > 0) ? new byte[primDataSize] : null;
2643 if (primDataSize > 0) {
2644 bin.readFully(primValues, 0, primDataSize, false);
2645 }
2646
2647
2648 int numObjFields = desc.getNumObjFields();
2649 objValues = (numObjFields > 0) ? new Object[numObjFields] : null;
2650 objHandles = (numObjFields > 0) ? new int[numObjFields] : null;
2651 if (numObjFields > 0) {
2652 int objHandle = passHandle;
2653 ObjectStreamField[] fields = desc.getFields(false);
2654 int numPrimFields = fields.length - objValues.length;
2655 for (int i = 0; i < objValues.length; i++) {
2656 ObjectStreamField f = fields[numPrimFields + i];
2657 objValues[i] = readObject0(Object.class, f.isUnshared());
2658 objHandles[i] = passHandle;
2659 if (recordDependencies && f.getField() != null) {
2660 handles.markDependency(objHandle, passHandle);
2661 }
2662 }
2663 passHandle = objHandle;
2664 }
2665 } catch (IOException ioe) {
2666 throw new UncheckedIOException(ioe);
2667 }
2668 }
2669
2670 public ObjectStreamClass getObjectStreamClass() {
2671 return desc;
2672 }
2673
2674 public boolean defaulted(String name) {
2675 return (getFieldOffset(name, null) < 0);
2676 }
2677
2678 public boolean get(String name, boolean val) {
2679 int off = getFieldOffset(name, Boolean.TYPE);
2680 return (off >= 0) ? ByteArray.getBoolean(primValues, off) : val;
2681 }
2682
2683 public byte get(String name, byte val) {
2684 int off = getFieldOffset(name, Byte.TYPE);
2685 return (off >= 0) ? primValues[off] : val;
2686 }
2687
2688 public char get(String name, char val) {
2689 int off = getFieldOffset(name, Character.TYPE);
2690 return (off >= 0) ? ByteArray.getChar(primValues, off) : val;
2691 }
2692
2693 public short get(String name, short val) {
2694 int off = getFieldOffset(name, Short.TYPE);
2695 return (off >= 0) ? ByteArray.getShort(primValues, off) : val;
2696 }
2697
2698 public int get(String name, int val) {
2699 int off = getFieldOffset(name, Integer.TYPE);
2700 return (off >= 0) ? ByteArray.getInt(primValues, off) : val;
2701 }
2702
2703 public float get(String name, float val) {
2704 int off = getFieldOffset(name, Float.TYPE);
2705 return (off >= 0) ? ByteArray.getFloat(primValues, off) : val;
2706 }
2707
2708 public long get(String name, long val) {
2709 int off = getFieldOffset(name, Long.TYPE);
2710 return (off >= 0) ? ByteArray.getLong(primValues, off) : val;
2711 }
2712
2713 public double get(String name, double val) {
2714 int off = getFieldOffset(name, Double.TYPE);
2715 return (off >= 0) ? ByteArray.getDouble(primValues, off) : val;
2716 }
2717
2718 public Object get(String name, Object val) throws ClassNotFoundException {
2719 int off = getFieldOffset(name, Object.class);
2720 if (off >= 0) {
2721 int objHandle = objHandles[off];
2722 handles.markDependency(passHandle, objHandle);
2723 ClassNotFoundException ex = handles.lookupException(objHandle);
2724 if (ex == null)
2725 return objValues[off];
2726 if (Caches.GETFIELD_CNFE_RETURNS_NULL) {
2727 // Revert to the prior behavior; return null instead of CNFE
2728 return null;
2729 }
2730 throw ex;
2731 } else {
2732 return val;
2733 }
2734 }
2735
2736 /** Throws ClassCastException if any value is not assignable. */
2737 void defaultCheckFieldValues(Object obj) {
2738 if (objValues != null)
2739 desc.checkObjFieldValueTypes(obj, objValues);
2740 }
2741
2742 private void defaultSetFieldValues(Object obj) {
2743 if (primValues != null)
2744 desc.setPrimFieldValues(obj, primValues);
2745 if (objValues != null)
2746 desc.setObjFieldValues(obj, objValues);
2747 }
2748
2749 /**
2750 * Returns offset of field with given name and type. A specified type
2751 * of null matches all types, Object.class matches all non-primitive
2752 * types, and any other non-null type matches assignable types only.
2753 * If no matching field is found in the (incoming) class
2754 * descriptor but a matching field is present in the associated local
2755 * class descriptor, returns -1. Throws IllegalArgumentException if
2756 * neither incoming nor local class descriptor contains a match.
2757 */
2758 private int getFieldOffset(String name, Class<?> type) {
2759 ObjectStreamField field = desc.getField(name, type);
2760 if (field != null) {
2761 return field.getOffset();
2762 } else if (desc.getLocalDesc().getField(name, type) != null) {
2763 return -1;
2764 } else {
2765 throw new IllegalArgumentException("no such field " + name +
2766 " with type " + type);
2767 }
2768 }
2769 }
2770
2771 /**
2772 * Prioritized list of callbacks to be performed once object graph has been
2773 * completely deserialized.
2774 */
2775 private static class ValidationList {
2776
2777 private static class Callback {
2778 final ObjectInputValidation obj;
2779 final int priority;
2780 Callback next;
2781
2782 Callback(ObjectInputValidation obj, int priority, Callback next) {
2783 this.obj = obj;
2784 this.priority = priority;
2785 this.next = next;
2786 }
2787 }
2788
2789 /** linked list of callbacks */
2790 private Callback list;
2791
2792 /**
2793 * Creates new (empty) ValidationList.
2794 */
2795 ValidationList() {
2796 }
2797
2798 /**
2799 * Registers callback. Throws InvalidObjectException if callback
2800 * object is null.
2801 */
2802 void register(ObjectInputValidation obj, int priority)
2803 throws InvalidObjectException
2804 {
2805 if (obj == null) {
2806 throw new InvalidObjectException("null callback");
2807 }
2808
2809 Callback prev = null, cur = list;
2810 while (cur != null && priority < cur.priority) {
2811 prev = cur;
2812 cur = cur.next;
2813 }
2814 if (prev != null) {
2815 prev.next = new Callback(obj, priority, cur);
2816 } else {
2817 list = new Callback(obj, priority, list);
2818 }
2819 }
2820
2821 /**
2822 * Invokes all registered callbacks and clears the callback list.
2823 * Callbacks with higher priorities are called first; those with equal
2824 * priorities may be called in any order. If any of the callbacks
2825 * throws an InvalidObjectException, the callback process is terminated
2826 * and the exception propagated upwards.
2827 */
2828 void doCallbacks() throws InvalidObjectException {
2829 try {
2830 while (list != null) {
2831 list.obj.validateObject();
2832 list = list.next;
2833 }
2834 } catch (InvalidObjectException ex) {
2835 list = null;
2836 throw ex;
2837 }
2838 }
2839
2840 /**
2841 * Resets the callback list to its initial (empty) state.
2842 */
2843 public void clear() {
2844 list = null;
2845 }
2846 }
2847
2848 /**
2849 * Hold a snapshot of values to be passed to an ObjectInputFilter.
2850 */
2851 static class FilterValues implements ObjectInputFilter.FilterInfo {
2852 final Class<?> clazz;
2853 final long arrayLength;
2854 final long totalObjectRefs;
2855 final long depth;
2856 final long streamBytes;
2857
2858 public FilterValues(Class<?> clazz, long arrayLength, long totalObjectRefs,
2859 long depth, long streamBytes) {
2860 this.clazz = clazz;
2861 this.arrayLength = arrayLength;
2862 this.totalObjectRefs = totalObjectRefs;
2863 this.depth = depth;
2864 this.streamBytes = streamBytes;
2865 }
2866
2867 @Override
2868 public Class<?> serialClass() {
2869 return clazz;
2870 }
2871
2872 @Override
2873 public long arrayLength() {
2874 return arrayLength;
2875 }
2876
2877 @Override
2878 public long references() {
2879 return totalObjectRefs;
2880 }
2881
2882 @Override
2883 public long depth() {
2884 return depth;
2885 }
2886
2887 @Override
2888 public long streamBytes() {
2889 return streamBytes;
2890 }
2891 }
2892
2893 /**
2894 * Input stream supporting single-byte peek operations.
2895 */
2896 private static class PeekInputStream extends InputStream {
2897
2898 /** underlying stream */
2899 private final InputStream in;
2900 /** peeked byte */
2901 private int peekb = -1;
2902 /** total bytes read from the stream */
2903 private long totalBytesRead = 0;
2904
2905 /**
2906 * Creates new PeekInputStream on top of given underlying stream.
2907 */
2908 PeekInputStream(InputStream in) {
2909 this.in = in;
2910 }
2911
2912 /**
2913 * Peeks at next byte value in stream. Similar to read(), except
2914 * that it does not consume the read value.
2915 */
2916 int peek() throws IOException {
2917 if (peekb >= 0) {
2918 return peekb;
2919 }
2920 peekb = in.read();
2921 totalBytesRead += peekb >= 0 ? 1 : 0;
2922 return peekb;
2923 }
2924
2925 public int read() throws IOException {
2926 if (peekb >= 0) {
2927 int v = peekb;
2928 peekb = -1;
2929 return v;
2930 } else {
2931 int nbytes = in.read();
2932 totalBytesRead += nbytes >= 0 ? 1 : 0;
2933 return nbytes;
2934 }
2935 }
2936
2937 public int read(byte[] b, int off, int len) throws IOException {
2938 int nbytes;
2939 if (len == 0) {
2940 return 0;
2941 } else if (peekb < 0) {
2942 nbytes = in.read(b, off, len);
2943 totalBytesRead += nbytes >= 0 ? nbytes : 0;
2944 return nbytes;
2945 } else {
2946 b[off++] = (byte) peekb;
2947 len--;
2948 peekb = -1;
2949 nbytes = in.read(b, off, len);
2950 totalBytesRead += nbytes >= 0 ? nbytes : 0;
2951 return (nbytes >= 0) ? (nbytes + 1) : 1;
2952 }
2953 }
2954
2955 void readFully(byte[] b, int off, int len) throws IOException {
2956 int n = 0;
2957 while (n < len) {
2958 int count = read(b, off + n, len - n);
2959 if (count < 0) {
2960 throw new EOFException();
2961 }
2962 n += count;
2963 }
2964 }
2965
2966 public long skip(long n) throws IOException {
2967 if (n <= 0) {
2968 return 0;
2969 }
2970 int skipped = 0;
2971 if (peekb >= 0) {
2972 peekb = -1;
2973 skipped++;
2974 n--;
2975 }
2976 n = skipped + in.skip(n);
2977 totalBytesRead += n;
2978 return n;
2979 }
2980
2981 public int available() throws IOException {
2982 return in.available() + ((peekb >= 0) ? 1 : 0);
2983 }
2984
2985 public void close() throws IOException {
2986 in.close();
2987 }
2988
2989 public long getBytesRead() {
2990 return totalBytesRead;
2991 }
2992 }
2993
2994 private static final Unsafe UNSAFE = Unsafe.getUnsafe();
2995
2996 /**
2997 * Performs a "freeze" action, required to adhere to final field semantics.
2998 *
2999 * <p> This method can be called unconditionally before returning the graph,
3000 * from the topmost readObject call, since it is expected that the
3001 * additional cost of the freeze action is negligible compared to
3002 * reconstituting even the most simple graph.
3003 *
3004 * <p> Nested calls to readObject do not issue freeze actions because the
3005 * sub-graph returned from a nested call is not guaranteed to be fully
3006 * initialized yet (possible cycles).
3007 */
3008 private void freeze() {
3009 // Issue a StoreStore|StoreLoad fence, which is at least sufficient
3010 // to provide final-freeze semantics.
3011 UNSAFE.storeFence();
3012 }
3013
3014 /**
3015 * Input stream with two modes: in default mode, inputs data written in the
3016 * same format as DataOutputStream; in "block data" mode, inputs data
3017 * bracketed by block data markers (see object serialization specification
3018 * for details). Buffering depends on block data mode: when in default
3019 * mode, no data is buffered in advance; when in block data mode, all data
3020 * for the current data block is read in at once (and buffered).
3021 */
3022 private class BlockDataInputStream
3023 extends InputStream implements DataInput
3024 {
3025 /** maximum data block length */
3026 private static final int MAX_BLOCK_SIZE = 1024;
3027 /** maximum data block header length */
3028 private static final int MAX_HEADER_SIZE = 5;
3029 /** (tunable) length of char buffer (for reading strings) */
3030 private static final int CHAR_BUF_SIZE = 256;
3031 /** readBlockHeader() return value indicating header read may block */
3032 private static final int HEADER_BLOCKED = -2;
3033 /** access to internal methods to count ASCII and inflate latin1/ASCII bytes to char */
3034 private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
3035
3036 /** buffer for reading general/block data */
3037 private final byte[] buf = new byte[MAX_BLOCK_SIZE];
3038 /** buffer for reading block data headers */
3039 private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
3040 /** char buffer for fast string reads */
3041 private final char[] cbuf = new char[CHAR_BUF_SIZE];
3042
3043 /** block data mode */
3044 private boolean blkmode = false;
3045
3046 // block data state fields; values meaningful only when blkmode true
3047 /** current offset into buf */
3048 private int pos = 0;
3049 /** end offset of valid data in buf, or -1 if no more block data */
3050 private int end = -1;
3051 /** number of bytes in current block yet to be read from stream */
3052 private int unread = 0;
3053
3054 /** underlying stream (wrapped in peekable filter stream) */
3055 private final PeekInputStream in;
3056 /** loopback stream (for data reads that span data blocks) */
3057 private final DataInputStream din;
3058
3059 /**
3060 * Creates new BlockDataInputStream on top of given underlying stream.
3061 * Block data mode is turned off by default.
3062 */
3063 BlockDataInputStream(InputStream in) {
3064 this.in = new PeekInputStream(in);
3065 din = new DataInputStream(this);
3066 }
3067
3068 /**
3069 * Sets block data mode to the given mode (true == on, false == off)
3070 * and returns the previous mode value. If the new mode is the same as
3071 * the old mode, no action is taken. Throws IllegalStateException if
3072 * block data mode is being switched from on to off while unconsumed
3073 * block data is still present in the stream.
3074 */
3075 boolean setBlockDataMode(boolean newmode) throws IOException {
3076 if (blkmode == newmode) {
3077 return blkmode;
3078 }
3079 if (newmode) {
3080 pos = 0;
3081 end = 0;
3082 unread = 0;
3083 } else if (pos < end) {
3084 throw new IllegalStateException("unread block data");
3085 }
3086 blkmode = newmode;
3087 return !blkmode;
3088 }
3089
3090 /**
3091 * Returns true if the stream is currently in block data mode, false
3092 * otherwise.
3093 */
3094 boolean getBlockDataMode() {
3095 return blkmode;
3096 }
3097
3098 /**
3099 * If in block data mode, skips to the end of the current group of data
3100 * blocks (but does not unset block data mode). If not in block data
3101 * mode, throws an IllegalStateException.
3102 */
3103 void skipBlockData() throws IOException {
3104 if (!blkmode) {
3105 throw new IllegalStateException("not in block data mode");
3106 }
3107 while (end >= 0) {
3108 refill();
3109 }
3110 }
3111
3112 /**
3113 * Attempts to read in the next block data header (if any). If
3114 * canBlock is false and a full header cannot be read without possibly
3115 * blocking, returns HEADER_BLOCKED, else if the next element in the
3116 * stream is a block data header, returns the block data length
3117 * specified by the header, else returns -1.
3118 */
3119 private int readBlockHeader(boolean canBlock) throws IOException {
3120 if (defaultDataEnd) {
3121 /*
3122 * Fix for 4360508: stream is currently at the end of a field
3123 * value block written via default serialization; since there
3124 * is no terminating TC_ENDBLOCKDATA tag, simulate
3125 * end-of-custom-data behavior explicitly.
3126 */
3127 return -1;
3128 }
3129 try {
3130 for (;;) {
3131 int avail = canBlock ? Integer.MAX_VALUE : in.available();
3132 if (avail == 0) {
3133 return HEADER_BLOCKED;
3134 }
3135
3136 int tc = in.peek();
3137 switch (tc) {
3138 case TC_BLOCKDATA:
3139 if (avail < 2) {
3140 return HEADER_BLOCKED;
3141 }
3142 in.readFully(hbuf, 0, 2);
3143 return hbuf[1] & 0xFF;
3144
3145 case TC_BLOCKDATALONG:
3146 if (avail < 5) {
3147 return HEADER_BLOCKED;
3148 }
3149 in.readFully(hbuf, 0, 5);
3150 int len = ByteArray.getInt(hbuf, 1);
3151 if (len < 0) {
3152 throw new StreamCorruptedException(
3153 "illegal block data header length: " +
3154 len);
3155 }
3156 return len;
3157
3158 /*
3159 * TC_RESETs may occur in between data blocks.
3160 * Unfortunately, this case must be parsed at a lower
3161 * level than other typecodes, since primitive data
3162 * reads may span data blocks separated by a TC_RESET.
3163 */
3164 case TC_RESET:
3165 in.read();
3166 handleReset();
3167 break;
3168
3169 default:
3170 if (tc >= 0 && (tc < TC_BASE || tc > TC_MAX)) {
3171 throw new StreamCorruptedException(
3172 String.format("invalid type code: %02X",
3173 tc));
3174 }
3175 return -1;
3176 }
3177 }
3178 } catch (EOFException ex) {
3179 throw new StreamCorruptedException(
3180 "unexpected EOF while reading block data header");
3181 }
3182 }
3183
3184 /**
3185 * Refills internal buffer buf with block data. Any data in buf at the
3186 * time of the call is considered consumed. Sets the pos, end, and
3187 * unread fields to reflect the new amount of available block data; if
3188 * the next element in the stream is not a data block, sets pos and
3189 * unread to 0 and end to -1.
3190 */
3191 private void refill() throws IOException {
3192 try {
3193 do {
3194 pos = 0;
3195 if (unread > 0) {
3196 int n =
3197 in.read(buf, 0, Math.min(unread, MAX_BLOCK_SIZE));
3198 if (n >= 0) {
3199 end = n;
3200 unread -= n;
3201 } else {
3202 throw new StreamCorruptedException(
3203 "unexpected EOF in middle of data block");
3204 }
3205 } else {
3206 int n = readBlockHeader(true);
3207 if (n >= 0) {
3208 end = 0;
3209 unread = n;
3210 } else {
3211 end = -1;
3212 unread = 0;
3213 }
3214 }
3215 } while (pos == end);
3216 } catch (IOException ex) {
3217 pos = 0;
3218 end = -1;
3219 unread = 0;
3220 throw ex;
3221 }
3222 }
3223
3224 /**
3225 * If in block data mode, returns the number of unconsumed bytes
3226 * remaining in the current data block. If not in block data mode,
3227 * throws an IllegalStateException.
3228 */
3229 int currentBlockRemaining() {
3230 if (blkmode) {
3231 return (end >= 0) ? (end - pos) + unread : 0;
3232 } else {
3233 throw new IllegalStateException();
3234 }
3235 }
3236
3237 /**
3238 * Peeks at (but does not consume) and returns the next byte value in
3239 * the stream, or -1 if the end of the stream/block data (if in block
3240 * data mode) has been reached.
3241 */
3242 int peek() throws IOException {
3243 if (blkmode) {
3244 if (pos == end) {
3245 refill();
3246 }
3247 return (end >= 0) ? (buf[pos] & 0xFF) : -1;
3248 } else {
3249 return in.peek();
3250 }
3251 }
3252
3253 /**
3254 * Peeks at (but does not consume) and returns the next byte value in
3255 * the stream, or throws EOFException if end of stream/block data has
3256 * been reached.
3257 */
3258 byte peekByte() throws IOException {
3259 int val = peek();
3260 if (val < 0) {
3261 throw new EOFException();
3262 }
3263 return (byte) val;
3264 }
3265
3266
3267 /* ----------------- generic input stream methods ------------------ */
3268 /*
3269 * The following methods are equivalent to their counterparts in
3270 * InputStream, except that they interpret data block boundaries and
3271 * read the requested data from within data blocks when in block data
3272 * mode.
3273 */
3274
3275 public int read() throws IOException {
3276 if (blkmode) {
3277 if (pos == end) {
3278 refill();
3279 }
3280 return (end >= 0) ? (buf[pos++] & 0xFF) : -1;
3281 } else {
3282 return in.read();
3283 }
3284 }
3285
3286 public int read(byte[] b, int off, int len) throws IOException {
3287 return read(b, off, len, false);
3288 }
3289
3290 public long skip(long len) throws IOException {
3291 long remain = len;
3292 while (remain > 0) {
3293 if (blkmode) {
3294 if (pos == end) {
3295 refill();
3296 }
3297 if (end < 0) {
3298 break;
3299 }
3300 int nread = (int) Math.min(remain, end - pos);
3301 remain -= nread;
3302 pos += nread;
3303 } else {
3304 int nread = (int) Math.min(remain, MAX_BLOCK_SIZE);
3305 if ((nread = in.read(buf, 0, nread)) < 0) {
3306 break;
3307 }
3308 remain -= nread;
3309 }
3310 }
3311 return len - remain;
3312 }
3313
3314 public int available() throws IOException {
3315 if (blkmode) {
3316 if ((pos == end) && (unread == 0)) {
3317 int n;
3318 while ((n = readBlockHeader(false)) == 0) ;
3319 switch (n) {
3320 case HEADER_BLOCKED:
3321 break;
3322
3323 case -1:
3324 pos = 0;
3325 end = -1;
3326 break;
3327
3328 default:
3329 pos = 0;
3330 end = 0;
3331 unread = n;
3332 break;
3333 }
3334 }
3335 // avoid unnecessary call to in.available() if possible
3336 int unreadAvail = (unread > 0) ?
3337 Math.min(in.available(), unread) : 0;
3338 return (end >= 0) ? (end - pos) + unreadAvail : 0;
3339 } else {
3340 return in.available();
3341 }
3342 }
3343
3344 public void close() throws IOException {
3345 if (blkmode) {
3346 pos = 0;
3347 end = -1;
3348 unread = 0;
3349 }
3350 in.close();
3351 }
3352
3353 /**
3354 * Attempts to read len bytes into byte array b at offset off. Returns
3355 * the number of bytes read, or -1 if the end of stream/block data has
3356 * been reached. If copy is true, reads values into an intermediate
3357 * buffer before copying them to b (to avoid exposing a reference to
3358 * b).
3359 */
3360 int read(byte[] b, int off, int len, boolean copy) throws IOException {
3361 if (len == 0) {
3362 return 0;
3363 } else if (blkmode) {
3364 if (pos == end) {
3365 refill();
3366 }
3367 if (end < 0) {
3368 return -1;
3369 }
3370 int nread = Math.min(len, end - pos);
3371 System.arraycopy(buf, pos, b, off, nread);
3372 pos += nread;
3373 return nread;
3374 } else if (copy) {
3375 int nread = in.read(buf, 0, Math.min(len, MAX_BLOCK_SIZE));
3376 if (nread > 0) {
3377 System.arraycopy(buf, 0, b, off, nread);
3378 }
3379 return nread;
3380 } else {
3381 return in.read(b, off, len);
3382 }
3383 }
3384
3385 /* ----------------- primitive data input methods ------------------ */
3386 /*
3387 * The following methods are equivalent to their counterparts in
3388 * DataInputStream, except that they interpret data block boundaries
3389 * and read the requested data from within data blocks when in block
3390 * data mode.
3391 */
3392
3393 public void readFully(byte[] b) throws IOException {
3394 readFully(b, 0, b.length, false);
3395 }
3396
3397 public void readFully(byte[] b, int off, int len) throws IOException {
3398 readFully(b, off, len, false);
3399 }
3400
3401 public void readFully(byte[] b, int off, int len, boolean copy)
3402 throws IOException
3403 {
3404 while (len > 0) {
3405 int n = read(b, off, len, copy);
3406 if (n < 0) {
3407 throw new EOFException();
3408 }
3409 off += n;
3410 len -= n;
3411 }
3412 }
3413
3414 public int skipBytes(int n) throws IOException {
3415 return din.skipBytes(n);
3416 }
3417
3418 public boolean readBoolean() throws IOException {
3419 int v = read();
3420 if (v < 0) {
3421 throw new EOFException();
3422 }
3423 return (v != 0);
3424 }
3425
3426 public byte readByte() throws IOException {
3427 int v = read();
3428 if (v < 0) {
3429 throw new EOFException();
3430 }
3431 return (byte) v;
3432 }
3433
3434 public int readUnsignedByte() throws IOException {
3435 int v = read();
3436 if (v < 0) {
3437 throw new EOFException();
3438 }
3439 return v;
3440 }
3441
3442 public char readChar() throws IOException {
3443 if (!blkmode) {
3444 pos = 0;
3445 in.readFully(buf, 0, 2);
3446 } else if (end - pos < 2) {
3447 return din.readChar();
3448 }
3449 char v = ByteArray.getChar(buf, pos);
3450 pos += 2;
3451 return v;
3452 }
3453
3454 public short readShort() throws IOException {
3455 if (!blkmode) {
3456 pos = 0;
3457 in.readFully(buf, 0, 2);
3458 } else if (end - pos < 2) {
3459 return din.readShort();
3460 }
3461 short v = ByteArray.getShort(buf, pos);
3462 pos += 2;
3463 return v;
3464 }
3465
3466 public int readUnsignedShort() throws IOException {
3467 if (!blkmode) {
3468 pos = 0;
3469 in.readFully(buf, 0, 2);
3470 } else if (end - pos < 2) {
3471 return din.readUnsignedShort();
3472 }
3473 int v = ByteArray.getShort(buf, pos) & 0xFFFF;
3474 pos += 2;
3475 return v;
3476 }
3477
3478 public int readInt() throws IOException {
3479 if (!blkmode) {
3480 pos = 0;
3481 in.readFully(buf, 0, 4);
3482 } else if (end - pos < 4) {
3483 return din.readInt();
3484 }
3485 int v = ByteArray.getInt(buf, pos);
3486 pos += 4;
3487 return v;
3488 }
3489
3490 public float readFloat() throws IOException {
3491 if (!blkmode) {
3492 pos = 0;
3493 in.readFully(buf, 0, 4);
3494 } else if (end - pos < 4) {
3495 return din.readFloat();
3496 }
3497 float v = ByteArray.getFloat(buf, pos);
3498 pos += 4;
3499 return v;
3500 }
3501
3502 public long readLong() throws IOException {
3503 if (!blkmode) {
3504 pos = 0;
3505 in.readFully(buf, 0, 8);
3506 } else if (end - pos < 8) {
3507 return din.readLong();
3508 }
3509 long v = ByteArray.getLong(buf, pos);
3510 pos += 8;
3511 return v;
3512 }
3513
3514 public double readDouble() throws IOException {
3515 if (!blkmode) {
3516 pos = 0;
3517 in.readFully(buf, 0, 8);
3518 } else if (end - pos < 8) {
3519 return din.readDouble();
3520 }
3521 double v = ByteArray.getDouble(buf, pos);
3522 pos += 8;
3523 return v;
3524 }
3525
3526 public String readUTF() throws IOException {
3527 return readUTFBody(readUnsignedShort());
3528 }
3529
3530 @SuppressWarnings("deprecation")
3531 public String readLine() throws IOException {
3532 return din.readLine(); // deprecated, not worth optimizing
3533 }
3534
3535 /* -------------- primitive data array input methods --------------- */
3536 /*
3537 * The following methods read in spans of primitive data values.
3538 * Though equivalent to calling the corresponding primitive read
3539 * methods repeatedly, these methods are optimized for reading groups
3540 * of primitive data values more efficiently.
3541 */
3542
3543 void readBooleans(boolean[] v, int off, int len) throws IOException {
3544 int stop, endoff = off + len;
3545 while (off < endoff) {
3546 if (!blkmode) {
3547 int span = Math.min(endoff - off, MAX_BLOCK_SIZE);
3548 in.readFully(buf, 0, span);
3549 stop = off + span;
3550 pos = 0;
3551 } else if (end - pos < 1) {
3552 v[off++] = din.readBoolean();
3553 continue;
3554 } else {
3555 stop = Math.min(endoff, off + end - pos);
3556 }
3557
3558 while (off < stop) {
3559 v[off++] = ByteArray.getBoolean(buf, pos++);
3560 }
3561 }
3562 }
3563
3564 void readChars(char[] v, int off, int len) throws IOException {
3565 int stop, endoff = off + len;
3566 while (off < endoff) {
3567 if (!blkmode) {
3568 int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
3569 in.readFully(buf, 0, span << 1);
3570 stop = off + span;
3571 pos = 0;
3572 } else if (end - pos < 2) {
3573 v[off++] = din.readChar();
3574 continue;
3575 } else {
3576 stop = Math.min(endoff, off + ((end - pos) >> 1));
3577 }
3578
3579 while (off < stop) {
3580 v[off++] = ByteArray.getChar(buf, pos);
3581 pos += 2;
3582 }
3583 }
3584 }
3585
3586 void readShorts(short[] v, int off, int len) throws IOException {
3587 int stop, endoff = off + len;
3588 while (off < endoff) {
3589 if (!blkmode) {
3590 int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
3591 in.readFully(buf, 0, span << 1);
3592 stop = off + span;
3593 pos = 0;
3594 } else if (end - pos < 2) {
3595 v[off++] = din.readShort();
3596 continue;
3597 } else {
3598 stop = Math.min(endoff, off + ((end - pos) >> 1));
3599 }
3600
3601 while (off < stop) {
3602 v[off++] = ByteArray.getShort(buf, pos);
3603 pos += 2;
3604 }
3605 }
3606 }
3607
3608 void readInts(int[] v, int off, int len) throws IOException {
3609 int stop, endoff = off + len;
3610 while (off < endoff) {
3611 if (!blkmode) {
3612 int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
3613 in.readFully(buf, 0, span << 2);
3614 stop = off + span;
3615 pos = 0;
3616 } else if (end - pos < 4) {
3617 v[off++] = din.readInt();
3618 continue;
3619 } else {
3620 stop = Math.min(endoff, off + ((end - pos) >> 2));
3621 }
3622
3623 while (off < stop) {
3624 v[off++] = ByteArray.getInt(buf, pos);
3625 pos += 4;
3626 }
3627 }
3628 }
3629
3630 void readFloats(float[] v, int off, int len) throws IOException {
3631 int stop, endoff = off + len;
3632 while (off < endoff) {
3633 if (!blkmode) {
3634 int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
3635 in.readFully(buf, 0, span << 2);
3636 stop = off + span;
3637 pos = 0;
3638 } else if (end - pos < 4) {
3639 v[off++] = din.readFloat();
3640 continue;
3641 } else {
3642 stop = Math.min(endoff, ((end - pos) >> 2));
3643 }
3644
3645 while (off < stop) {
3646 v[off++] = ByteArray.getFloat(buf, pos);
3647 pos += 4;
3648 }
3649 }
3650 }
3651
3652 void readLongs(long[] v, int off, int len) throws IOException {
3653 int stop, endoff = off + len;
3654 while (off < endoff) {
3655 if (!blkmode) {
3656 int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
3657 in.readFully(buf, 0, span << 3);
3658 stop = off + span;
3659 pos = 0;
3660 } else if (end - pos < 8) {
3661 v[off++] = din.readLong();
3662 continue;
3663 } else {
3664 stop = Math.min(endoff, off + ((end - pos) >> 3));
3665 }
3666
3667 while (off < stop) {
3668 v[off++] = ByteArray.getLong(buf, pos);
3669 pos += 8;
3670 }
3671 }
3672 }
3673
3674 void readDoubles(double[] v, int off, int len) throws IOException {
3675 int stop, endoff = off + len;
3676 while (off < endoff) {
3677 if (!blkmode) {
3678 int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
3679 in.readFully(buf, 0, span << 3);
3680 stop = off + span;
3681 pos = 0;
3682 } else if (end - pos < 8) {
3683 v[off++] = din.readDouble();
3684 continue;
3685 } else {
3686 stop = Math.min(endoff - off, ((end - pos) >> 3));
3687 }
3688
3689 while (off < stop) {
3690 v[off++] = ByteArray.getDouble(buf, pos);
3691 pos += 8;
3692 }
3693 }
3694 }
3695
3696 /**
3697 * Reads in string written in "long" UTF format. "Long" UTF format is
3698 * identical to standard UTF, except that it uses an 8 byte header
3699 * (instead of the standard 2 bytes) to convey the UTF encoding length.
3700 */
3701 String readLongUTF() throws IOException {
3702 return readUTFBody(readLong());
3703 }
3704
3705 /**
3706 * Reads in the "body" (i.e., the UTF representation minus the 2-byte
3707 * or 8-byte length header) of a UTF encoding, which occupies the next
3708 * utflen bytes.
3709 */
3710 private String readUTFBody(long utflen) throws IOException {
3711 if (!blkmode) {
3712 end = pos = 0;
3713 }
3714
3715 StringBuilder sbuf;
3716 if (utflen > 0 && utflen < Integer.MAX_VALUE) {
3717 // Scan for leading ASCII chars
3718 int avail = end - pos;
3719 int ascii = JLA.countPositives(buf, pos, Math.min(avail, (int)utflen));
3720 if (ascii == utflen) {
3721 // Complete match, consume the buf[pos ... pos + ascii] range and return.
3722 // Modified UTF-8 and ISO-8859-1 are both ASCII-compatible encodings bytes
3723 // thus we can treat the range as ISO-8859-1 and avoid a redundant scan
3724 // in the String constructor
3725 String utf = new String(buf, pos, ascii, StandardCharsets.ISO_8859_1);
3726 pos += ascii;
3727 return utf;
3728 }
3729 // Avoid allocating a StringBuilder if there's enough data in buf and
3730 // cbuf is large enough
3731 if (avail >= utflen && utflen <= CHAR_BUF_SIZE) {
3732 JLA.inflateBytesToChars(buf, pos, cbuf, 0, ascii);
3733 pos += ascii;
3734 int cbufPos = readUTFSpan(ascii, utflen - ascii);
3735 return new String(cbuf, 0, cbufPos);
3736 }
3737 // a reasonable initial capacity based on the UTF length
3738 int initialCapacity = Math.min((int)utflen, 0xFFFF);
3739 sbuf = new StringBuilder(initialCapacity);
3740 } else {
3741 sbuf = new StringBuilder();
3742 }
3743
3744 while (utflen > 0) {
3745 int avail = end - pos;
3746 if (avail >= 3 || (long) avail == utflen) {
3747 int cbufPos = readUTFSpan(0, utflen);
3748 // pos has advanced: adjust utflen by the difference in
3749 // available bytes
3750 utflen -= avail - (end - pos);
3751 sbuf.append(cbuf, 0, cbufPos);
3752 } else {
3753 if (blkmode) {
3754 // near block boundary, read one byte at a time
3755 utflen -= readUTFChar(sbuf, utflen);
3756 } else {
3757 // shift and refill buffer manually
3758 if (avail > 0) {
3759 System.arraycopy(buf, pos, buf, 0, avail);
3760 }
3761 pos = 0;
3762 end = (int) Math.min(MAX_BLOCK_SIZE, utflen);
3763 in.readFully(buf, avail, end - avail);
3764 }
3765 }
3766 }
3767
3768 return sbuf.toString();
3769 }
3770
3771 /**
3772 * Reads span of UTF-encoded characters out of internal buffer
3773 * (starting at offset pos), consuming no more than utflen bytes.
3774 * Appends read characters to cbuf. Returns the current position
3775 * in cbuf.
3776 */
3777 private int readUTFSpan(int cpos, long utflen)
3778 throws IOException
3779 {
3780 int start = pos;
3781 int avail = Math.min(end - pos, CHAR_BUF_SIZE);
3782 // stop short of last char unless all of utf bytes in buffer
3783 int stop = start + ((utflen > avail) ? avail - 2 : (int) utflen);
3784 boolean outOfBounds = false;
3785
3786 try {
3787 while (pos < stop) {
3788 int b1, b2, b3;
3789 b1 = buf[pos++] & 0xFF;
3790 switch (b1 >> 4) {
3791 case 0, 1, 2, 3, 4, 5, 6, 7 -> // 1 byte format: 0xxxxxxx
3792 cbuf[cpos++] = (char) b1;
3793 case 12, 13 -> { // 2 byte format: 110xxxxx 10xxxxxx
3794 b2 = buf[pos++];
3795 if ((b2 & 0xC0) != 0x80) {
3796 throw new UTFDataFormatException();
3797 }
3798 cbuf[cpos++] = (char) (((b1 & 0x1F) << 6) |
3799 ((b2 & 0x3F) << 0));
3800 }
3801 case 14 -> { // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
3802 b3 = buf[pos + 1];
3803 b2 = buf[pos + 0];
3804 pos += 2;
3805 if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
3806 throw new UTFDataFormatException();
3807 }
3808 cbuf[cpos++] = (char) (((b1 & 0x0F) << 12) |
3809 ((b2 & 0x3F) << 6) |
3810 ((b3 & 0x3F) << 0));
3811 }
3812 default -> throw new UTFDataFormatException(); // 10xx xxxx, 1111 xxxx
3813 }
3814 }
3815 } catch (ArrayIndexOutOfBoundsException ex) {
3816 outOfBounds = true;
3817 } finally {
3818 if (outOfBounds || (pos - start) > utflen) {
3819 /*
3820 * Fix for 4450867: if a malformed utf char causes the
3821 * conversion loop to scan past the expected end of the utf
3822 * string, only consume the expected number of utf bytes.
3823 */
3824 pos = start + (int) utflen;
3825 throw new UTFDataFormatException();
3826 }
3827 }
3828 return cpos;
3829 }
3830
3831 /**
3832 * Reads in single UTF-encoded character one byte at a time, appends
3833 * the character to sbuf, and returns the number of bytes consumed.
3834 * This method is used when reading in UTF strings written in block
3835 * data mode to handle UTF-encoded characters which (potentially)
3836 * straddle block-data boundaries.
3837 */
3838 private int readUTFChar(StringBuilder sbuf, long utflen)
3839 throws IOException
3840 {
3841 int b1, b2, b3;
3842 b1 = readByte() & 0xFF;
3843 switch (b1 >> 4) {
3844 case 0, 1, 2, 3, 4, 5, 6, 7 -> { // 1 byte format: 0xxxxxxx
3845 sbuf.append((char) b1);
3846 return 1;
3847 }
3848 case 12, 13 -> { // 2 byte format: 110xxxxx 10xxxxxx
3849 if (utflen < 2) {
3850 throw new UTFDataFormatException();
3851 }
3852 b2 = readByte();
3853 if ((b2 & 0xC0) != 0x80) {
3854 throw new UTFDataFormatException();
3855 }
3856 sbuf.append((char) (((b1 & 0x1F) << 6) |
3857 ((b2 & 0x3F) << 0)));
3858 return 2;
3859 }
3860 case 14 -> { // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
3861 if (utflen < 3) {
3862 if (utflen == 2) {
3863 readByte(); // consume remaining byte
3864 }
3865 throw new UTFDataFormatException();
3866 }
3867 b2 = readByte();
3868 b3 = readByte();
3869 if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
3870 throw new UTFDataFormatException();
3871 }
3872 sbuf.append((char) (((b1 & 0x0F) << 12) |
3873 ((b2 & 0x3F) << 6) |
3874 ((b3 & 0x3F) << 0)));
3875 return 3;
3876 }
3877 default -> throw new UTFDataFormatException(); // 10xx xxxx, 1111 xxxx
3878 }
3879 }
3880
3881 /**
3882 * {@return the number of bytes read from the input stream}
3883 */
3884 long getBytesRead() {
3885 return in.getBytesRead();
3886 }
3887 }
3888
3889 /**
3890 * Unsynchronized table which tracks wire handle to object mappings, as
3891 * well as ClassNotFoundExceptions associated with deserialized objects.
3892 * This class implements an exception-propagation algorithm for
3893 * determining which objects should have ClassNotFoundExceptions associated
3894 * with them, taking into account cycles and discontinuities (e.g., skipped
3895 * fields) in the object graph.
3896 *
3897 * <p>General use of the table is as follows: during deserialization, a
3898 * given object is first assigned a handle by calling the assign method.
3899 * This method leaves the assigned handle in an "open" state, wherein
3900 * dependencies on the exception status of other handles can be registered
3901 * by calling the markDependency method, or an exception can be directly
3902 * associated with the handle by calling markException. When a handle is
3903 * tagged with an exception, the HandleTable assumes responsibility for
3904 * propagating the exception to any other objects which depend
3905 * (transitively) on the exception-tagged object.
3906 *
3907 * <p>Once all exception information/dependencies for the handle have been
3908 * registered, the handle should be "closed" by calling the finish method
3909 * on it. The act of finishing a handle allows the exception propagation
3910 * algorithm to aggressively prune dependency links, lessening the
3911 * performance/memory impact of exception tracking.
3912 *
3913 * <p>Note that the exception propagation algorithm used depends on handles
3914 * being assigned/finished in LIFO order; however, for simplicity as well
3915 * as memory conservation, it does not enforce this constraint.
3916 */
3917 // REMIND: add full description of exception propagation algorithm?
3918 private static final class HandleTable {
3919
3920 /* status codes indicating whether object has associated exception */
3921 private static final byte STATUS_OK = 1;
3922 private static final byte STATUS_UNKNOWN = 2;
3923 private static final byte STATUS_EXCEPTION = 3;
3924
3925 /** array mapping handle -> object status */
3926 byte[] status;
3927 /** array mapping handle -> object/exception (depending on status) */
3928 Object[] entries;
3929 /** array mapping handle -> list of dependent handles (if any) */
3930 HandleList[] deps;
3931 /** lowest unresolved dependency */
3932 int lowDep = -1;
3933 /** number of handles in table */
3934 int size = 0;
3935
3936 /**
3937 * Creates handle table with the given initial capacity.
3938 */
3939 HandleTable(int initialCapacity) {
3940 status = new byte[initialCapacity];
3941 entries = new Object[initialCapacity];
3942 deps = new HandleList[initialCapacity];
3943 }
3944
3945 /**
3946 * Assigns next available handle to given object, and returns assigned
3947 * handle. Once object has been completely deserialized (and all
3948 * dependencies on other objects identified), the handle should be
3949 * "closed" by passing it to finish().
3950 */
3951 int assign(Object obj) {
3952 if (size >= entries.length) {
3953 grow();
3954 }
3955 status[size] = STATUS_UNKNOWN;
3956 entries[size] = obj;
3957 return size++;
3958 }
3959
3960 /**
3961 * Registers a dependency (in exception status) of one handle on
3962 * another. The dependent handle must be "open" (i.e., assigned, but
3963 * not finished yet). No action is taken if either dependent or target
3964 * handle is NULL_HANDLE. Additionally, no action is taken if the
3965 * dependent and target are the same.
3966 */
3967 void markDependency(int dependent, int target) {
3968 if (dependent == target || dependent == NULL_HANDLE || target == NULL_HANDLE) {
3969 return;
3970 }
3971 switch (status[dependent]) {
3972
3973 case STATUS_UNKNOWN:
3974 switch (status[target]) {
3975 case STATUS_OK:
3976 // ignore dependencies on objs with no exception
3977 break;
3978
3979 case STATUS_EXCEPTION:
3980 // eagerly propagate exception
3981 markException(dependent,
3982 (ClassNotFoundException) entries[target]);
3983 break;
3984
3985 case STATUS_UNKNOWN:
3986 // add to dependency list of target
3987 if (deps[target] == null) {
3988 deps[target] = new HandleList();
3989 }
3990 deps[target].add(dependent);
3991
3992 // remember lowest unresolved target seen
3993 if (lowDep < 0 || lowDep > target) {
3994 lowDep = target;
3995 }
3996 break;
3997
3998 default:
3999 throw new InternalError();
4000 }
4001 break;
4002
4003 case STATUS_EXCEPTION:
4004 break;
4005
4006 default:
4007 throw new InternalError();
4008 }
4009 }
4010
4011 /**
4012 * Associates a ClassNotFoundException (if one not already associated)
4013 * with the currently active handle and propagates it to other
4014 * referencing objects as appropriate. The specified handle must be
4015 * "open" (i.e., assigned, but not finished yet).
4016 */
4017 void markException(int handle, ClassNotFoundException ex) {
4018 switch (status[handle]) {
4019 case STATUS_UNKNOWN:
4020 status[handle] = STATUS_EXCEPTION;
4021 entries[handle] = ex;
4022
4023 // propagate exception to dependents
4024 HandleList dlist = deps[handle];
4025 if (dlist != null) {
4026 int ndeps = dlist.size();
4027 for (int i = 0; i < ndeps; i++) {
4028 markException(dlist.get(i), ex);
4029 }
4030 deps[handle] = null;
4031 }
4032 break;
4033
4034 case STATUS_EXCEPTION:
4035 break;
4036
4037 default:
4038 throw new InternalError();
4039 }
4040 }
4041
4042 /**
4043 * Marks given handle as finished, meaning that no new dependencies
4044 * will be marked for handle. Calls to the assign and finish methods
4045 * must occur in LIFO order.
4046 */
4047 void finish(int handle) {
4048 int end;
4049 if (lowDep < 0) {
4050 // no pending unknowns, only resolve current handle
4051 end = handle + 1;
4052 } else if (lowDep >= handle) {
4053 // pending unknowns now clearable, resolve all upward handles
4054 end = size;
4055 lowDep = -1;
4056 } else {
4057 // unresolved backrefs present, can't resolve anything yet
4058 return;
4059 }
4060
4061 // change STATUS_UNKNOWN -> STATUS_OK in selected span of handles
4062 for (int i = handle; i < end; i++) {
4063 switch (status[i]) {
4064 case STATUS_UNKNOWN:
4065 status[i] = STATUS_OK;
4066 deps[i] = null;
4067 break;
4068
4069 case STATUS_OK:
4070 case STATUS_EXCEPTION:
4071 break;
4072
4073 default:
4074 throw new InternalError();
4075 }
4076 }
4077 }
4078
4079 /**
4080 * Assigns a new object to the given handle. The object previously
4081 * associated with the handle is forgotten. This method has no effect
4082 * if the given handle already has an exception associated with it.
4083 * This method may be called at any time after the handle is assigned.
4084 */
4085 void setObject(int handle, Object obj) {
4086 switch (status[handle]) {
4087 case STATUS_UNKNOWN:
4088 case STATUS_OK:
4089 entries[handle] = obj;
4090 break;
4091
4092 case STATUS_EXCEPTION:
4093 break;
4094
4095 default:
4096 throw new InternalError();
4097 }
4098 }
4099
4100 /**
4101 * Looks up and returns object associated with the given handle.
4102 * Returns null if the given handle is NULL_HANDLE, or if it has an
4103 * associated ClassNotFoundException.
4104 */
4105 Object lookupObject(int handle) {
4106 return (handle != NULL_HANDLE &&
4107 status[handle] != STATUS_EXCEPTION) ?
4108 entries[handle] : null;
4109 }
4110
4111 /**
4112 * Looks up and returns ClassNotFoundException associated with the
4113 * given handle. Returns null if the given handle is NULL_HANDLE, or
4114 * if there is no ClassNotFoundException associated with the handle.
4115 */
4116 ClassNotFoundException lookupException(int handle) {
4117 return (handle != NULL_HANDLE &&
4118 status[handle] == STATUS_EXCEPTION) ?
4119 (ClassNotFoundException) entries[handle] : null;
4120 }
4121
4122 /**
4123 * Resets table to its initial state.
4124 */
4125 void clear() {
4126 Arrays.fill(status, 0, size, (byte) 0);
4127 Arrays.fill(entries, 0, size, null);
4128 Arrays.fill(deps, 0, size, null);
4129 lowDep = -1;
4130 size = 0;
4131 }
4132
4133 /**
4134 * Returns number of handles registered in table.
4135 */
4136 int size() {
4137 return size;
4138 }
4139
4140 /**
4141 * Expands capacity of internal arrays.
4142 */
4143 private void grow() {
4144 int newCapacity = (entries.length << 1) + 1;
4145
4146 byte[] newStatus = new byte[newCapacity];
4147 Object[] newEntries = new Object[newCapacity];
4148 HandleList[] newDeps = new HandleList[newCapacity];
4149
4150 System.arraycopy(status, 0, newStatus, 0, size);
4151 System.arraycopy(entries, 0, newEntries, 0, size);
4152 System.arraycopy(deps, 0, newDeps, 0, size);
4153
4154 status = newStatus;
4155 entries = newEntries;
4156 deps = newDeps;
4157 }
4158
4159 /**
4160 * Simple growable list of (integer) handles.
4161 */
4162 private static class HandleList {
4163 private int[] list = new int[4];
4164 private int size = 0;
4165
4166 public HandleList() {
4167 }
4168
4169 public void add(int handle) {
4170 if (size >= list.length) {
4171 int[] newList = new int[list.length << 1];
4172 System.arraycopy(list, 0, newList, 0, list.length);
4173 list = newList;
4174 }
4175 list[size++] = handle;
4176 }
4177
4178 public int get(int index) {
4179 if (index >= size) {
4180 throw new ArrayIndexOutOfBoundsException();
4181 }
4182 return list[index];
4183 }
4184
4185 public int size() {
4186 return size;
4187 }
4188 }
4189 }
4190
4191 /**
4192 * Method for cloning arrays in case of using unsharing reading
4193 */
4194 private static Object cloneArray(Object array) {
4195 if (array instanceof Object[]) {
4196 return ((Object[]) array).clone();
4197 } else if (array instanceof boolean[]) {
4198 return ((boolean[]) array).clone();
4199 } else if (array instanceof byte[]) {
4200 return ((byte[]) array).clone();
4201 } else if (array instanceof char[]) {
4202 return ((char[]) array).clone();
4203 } else if (array instanceof double[]) {
4204 return ((double[]) array).clone();
4205 } else if (array instanceof float[]) {
4206 return ((float[]) array).clone();
4207 } else if (array instanceof int[]) {
4208 return ((int[]) array).clone();
4209 } else if (array instanceof long[]) {
4210 return ((long[]) array).clone();
4211 } else if (array instanceof short[]) {
4212 return ((short[]) array).clone();
4213 } else {
4214 throw new AssertionError();
4215 }
4216 }
4217
4218 static {
4219 SharedSecrets.setJavaObjectInputStreamAccess(ObjectInputStream::checkArray);
4220 SharedSecrets.setJavaObjectInputStreamReadString(ObjectInputStream::readString);
4221 }
4222
4223 }