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