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