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