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