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