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 }