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