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