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