< prev index next >

src/java.base/share/classes/java/io/ObjectInputStream.java

Print this page

   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.io;
  27 
  28 import java.io.ObjectInputFilter.Config;
  29 import java.io.ObjectStreamClass.RecordSupport;

  30 import java.lang.System.Logger;
  31 import java.lang.invoke.MethodHandle;
  32 import java.lang.reflect.Array;
  33 import java.lang.reflect.InvocationHandler;

  34 import java.lang.reflect.Modifier;
  35 import java.lang.reflect.Proxy;
  36 import java.nio.charset.StandardCharsets;
  37 import java.security.AccessControlContext;
  38 import java.security.AccessController;
  39 import java.security.PrivilegedAction;
  40 import java.security.PrivilegedActionException;
  41 import java.security.PrivilegedExceptionAction;
  42 import java.util.Arrays;
  43 import java.util.Map;

  44 import java.util.Objects;
  45 
  46 import jdk.internal.access.JavaLangAccess;
  47 import jdk.internal.access.SharedSecrets;
  48 import jdk.internal.event.DeserializationEvent;
  49 import jdk.internal.misc.Unsafe;
  50 import jdk.internal.util.ByteArray;
  51 import sun.reflect.misc.ReflectUtil;
  52 import sun.security.action.GetBooleanAction;
  53 import sun.security.action.GetIntegerAction;

  54 
  55 /**
  56  * An ObjectInputStream deserializes primitive data and objects previously
  57  * written using an ObjectOutputStream.
  58  *
  59  * <p><strong>Warning: Deserialization of untrusted data is inherently dangerous
  60  * and should be avoided. Untrusted data should be carefully validated according to the
  61  * "Serialization and Deserialization" section of the
  62  * {@extLink secure_coding_guidelines_javase Secure Coding Guidelines for Java SE}.
  63  * {@extLink serialization_filter_guide Serialization Filtering} describes best
  64  * practices for defensive use of serial filters.
  65  * </strong></p>
  66  *
  67  * <p>The key to disabling deserialization attacks is to prevent instances of
  68  * arbitrary classes from being deserialized, thereby preventing the direct or
  69  * indirect execution of their methods.
  70  * {@link ObjectInputFilter} describes how to use filters and
  71  * {@link ObjectInputFilter.Config} describes how to configure the filter and filter factory.
  72  * Each stream has an optional deserialization filter
  73  * to check the classes and resource limits during deserialization.

 202  * <p>Serialization does not read or assign values to the fields of any object
 203  * that does not implement the java.io.Serializable interface.  Subclasses of
 204  * Objects that are not serializable can be serializable. In this case the
 205  * non-serializable class must have a no-arg constructor to allow its fields to
 206  * be initialized.  In this case it is the responsibility of the subclass to
 207  * save and restore the state of the non-serializable class. It is frequently
 208  * the case that the fields of that class are accessible (public, package, or
 209  * protected) or that there are get and set methods that can be used to restore
 210  * the state.
 211  *
 212  * <p>Any exception that occurs while deserializing an object will be caught by
 213  * the ObjectInputStream and abort the reading process.
 214  *
 215  * <p>Implementing the Externalizable interface allows the object to assume
 216  * complete control over the contents and format of the object's serialized
 217  * form.  The methods of the Externalizable interface, writeExternal and
 218  * readExternal, are called to save and restore the objects state.  When
 219  * implemented by a class they can write and read their own state using all of
 220  * the methods of ObjectOutput and ObjectInput.  It is the responsibility of
 221  * the objects to handle any versioning that occurs.


 222  *
 223  * <p>Enum constants are deserialized differently than ordinary serializable or
 224  * externalizable objects.  The serialized form of an enum constant consists
 225  * solely of its name; field values of the constant are not transmitted.  To
 226  * deserialize an enum constant, ObjectInputStream reads the constant name from
 227  * the stream; the deserialized constant is then obtained by calling the static
 228  * method {@code Enum.valueOf(Class, String)} with the enum constant's
 229  * base type and the received constant name as arguments.  Like other
 230  * serializable or externalizable objects, enum constants can function as the
 231  * targets of back references appearing subsequently in the serialization
 232  * stream.  The process by which enum constants are deserialized cannot be
 233  * customized: any class-specific readObject, readObjectNoData, and readResolve
 234  * methods defined by enum types are ignored during deserialization.
 235  * Similarly, any serialPersistentFields or serialVersionUID field declarations
 236  * are also ignored--all enum types have a fixed serialVersionUID of 0L.
 237  *
 238  * <a id="record-serialization"></a>
 239  * <p>Records are serialized differently than ordinary serializable or externalizable
 240  * objects. During deserialization the record's canonical constructor is invoked
 241  * to construct the record object. Certain serialization-related methods, such
 242  * as readObject and writeObject, are ignored for serializable records. See
 243  * <a href="{@docRoot}/../specs/serialization/serial-arch.html#serialization-of-records">
 244  * <cite>Java Object Serialization Specification,</cite> Section 1.13,
 245  * "Serialization of Records"</a> for additional information.
 246  *




 247  * @spec serialization/index.html Java Object Serialization Specification
 248  * @author      Mike Warres
 249  * @author      Roger Riggs
 250  * @see java.io.DataInput
 251  * @see java.io.ObjectOutputStream
 252  * @see java.io.Serializable
 253  * @see <a href="{@docRoot}/../specs/serialization/input.html">
 254  *      <cite>Java Object Serialization Specification,</cite> Section 3, "Object Input Classes"</a>
 255  * @since   1.1
 256  */
 257 public class ObjectInputStream
 258     extends InputStream implements ObjectInput, ObjectStreamConstants
 259 {










 260     /** handle value representing null */
 261     private static final int NULL_HANDLE = -1;
 262 
 263     /** marker for unshared objects in internal handle table */
 264     private static final Object unsharedMarker = new Object();
 265 
 266     private static class Caches {
 267         /** cache of subclass security audit results */
 268         static final ClassValue<Boolean> subclassAudits =
 269             new ClassValue<>() {
 270                 @Override
 271                 protected Boolean computeValue(Class<?> type) {
 272                     return auditSubclass(type);
 273                 }
 274             };
 275 
 276         /**
 277          * Property to permit setting a filter after objects
 278          * have been read.
 279          * See {@link #setObjectInputFilter(ObjectInputFilter)}

 449 
 450     /**
 451      * Read an object from the ObjectInputStream.  The class of the object, the
 452      * signature of the class, and the values of the non-transient and
 453      * non-static fields of the class and all of its supertypes are read.
 454      * Default deserializing for a class can be overridden using the writeObject
 455      * and readObject methods.  Objects referenced by this object are read
 456      * transitively so that a complete equivalent graph of objects is
 457      * reconstructed by readObject.
 458      *
 459      * <p>The root object is completely restored when all of its fields and the
 460      * objects it references are completely restored.  At this point the object
 461      * validation callbacks are executed in order based on their registered
 462      * priorities. The callbacks are registered by objects (in the readObject
 463      * special methods) as they are individually restored.
 464      *
 465      * <p>The deserialization filter, when not {@code null}, is invoked for
 466      * each object (regular or class) read to reconstruct the root object.
 467      * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
 468      *








 469      * <p>Exceptions are thrown for problems with the InputStream and for
 470      * classes that should not be deserialized.  All exceptions are fatal to
 471      * the InputStream and leave it in an indeterminate state; it is up to the
 472      * caller to ignore or recover the stream state.
 473      *
 474      * @throws  ClassNotFoundException Class of a serialized object cannot be
 475      *          found.
 476      * @throws  InvalidClassException Something is wrong with a class used by
 477      *          deserialization.
 478      * @throws  StreamCorruptedException Control information in the
 479      *          stream is inconsistent.
 480      * @throws  OptionalDataException Primitive data was found in the
 481      *          stream instead of objects.
 482      * @throws  IOException Any of the usual Input/Output related exceptions.
 483      */
 484     public final Object readObject()
 485         throws IOException, ClassNotFoundException {
 486         return readObject(Object.class);
 487     }
 488 

 582      *       to deserialize back-references to the stream handle deserialized
 583      *       by readUnshared will cause an ObjectStreamException to be thrown.
 584      * </ul>
 585      * Deserializing an object via readUnshared invalidates the stream handle
 586      * associated with the returned object.  Note that this in itself does not
 587      * always guarantee that the reference returned by readUnshared is unique;
 588      * the deserialized object may define a readResolve method which returns an
 589      * object visible to other parties, or readUnshared may return a Class
 590      * object or enum constant obtainable elsewhere in the stream or through
 591      * external means. If the deserialized object defines a readResolve method
 592      * and the invocation of that method returns an array, then readUnshared
 593      * returns a shallow clone of that array; this guarantees that the returned
 594      * array object is unique and cannot be obtained a second time from an
 595      * invocation of readObject or readUnshared on the ObjectInputStream,
 596      * even if the underlying data stream has been manipulated.
 597      *
 598      * <p>The deserialization filter, when not {@code null}, is invoked for
 599      * each object (regular or class) read to reconstruct the root object.
 600      * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
 601      *



 602      * <p>ObjectInputStream subclasses which override this method can only be
 603      * constructed in security contexts possessing the
 604      * "enableSubclassImplementation" SerializablePermission; any attempt to
 605      * instantiate such a subclass without this permission will cause a
 606      * SecurityException to be thrown.
 607      *
 608      * @return  reference to deserialized object
 609      * @throws  ClassNotFoundException if class of an object to deserialize
 610      *          cannot be found
 611      * @throws  StreamCorruptedException if control information in the stream
 612      *          is inconsistent
 613      * @throws  ObjectStreamException if object to deserialize has already
 614      *          appeared in stream
 615      * @throws  OptionalDataException if primitive data is next in stream
 616      * @throws  IOException if an I/O error occurs during deserialization
 617      * @since   1.4
 618      */
 619     public Object readUnshared() throws IOException, ClassNotFoundException {
 620         // if nested read, passHandle contains handle of enclosing object
 621         int outerHandle = passHandle;

2235      * class is unresolvable (in which case a ClassNotFoundException will be
2236      * associated with object's handle).  Sets passHandle to object's assigned
2237      * handle.
2238      */
2239     private Object readOrdinaryObject(boolean unshared)
2240         throws IOException
2241     {
2242         if (bin.readByte() != TC_OBJECT) {
2243             throw new InternalError();
2244         }
2245 
2246         ObjectStreamClass desc = readClassDesc(false);
2247         desc.checkDeserialize();
2248 
2249         Class<?> cl = desc.forClass();
2250         if (cl == String.class || cl == Class.class
2251                 || cl == ObjectStreamClass.class) {
2252             throw new InvalidClassException("invalid class descriptor");
2253         }
2254 
2255         Object obj;
2256         try {
2257             obj = desc.isInstantiable() ? desc.newInstance() : null;
2258         } catch (Exception ex) {
2259             throw new InvalidClassException(desc.forClass().getName(),
2260                                             "unable to create instance", ex);
2261         }
2262 
2263         passHandle = handles.assign(unshared ? unsharedMarker : obj);
2264         ClassNotFoundException resolveEx = desc.getResolveException();
2265         if (resolveEx != null) {
2266             handles.markException(passHandle, resolveEx);
2267         }
2268 
2269         final boolean isRecord = desc.isRecord();
2270         if (isRecord) {
2271             assert obj == null;
2272             obj = readRecord(desc);
2273             if (!unshared)
2274                 handles.setObject(passHandle, obj);
2275         } else if (desc.isExternalizable()) {
2276             readExternalData((Externalizable) obj, desc);
2277         } else {
2278             readSerialData(obj, desc);
2279         }

2280 
2281         handles.finish(passHandle);
2282 
2283         if (obj != null &&
2284             handles.lookupException(passHandle) == null &&
2285             desc.hasReadResolveMethod())
2286         {
2287             Object rep = desc.invokeReadResolve(obj);
2288             if (unshared && rep.getClass().isArray()) {
2289                 rep = cloneArray(rep);
2290             }
2291             if (rep != obj) {
2292                 // Filter the replacement object
2293                 if (rep != null) {
2294                     if (rep.getClass().isArray()) {
2295                         filterCheck(rep.getClass(), Array.getLength(rep));
2296                     } else {
2297                         filterCheck(rep.getClass(), -1);

2298                     }

2299                 }
2300                 handles.setObject(passHandle, obj = rep);































2301             }
2302         }


2303 
2304         return obj;














2305     }
2306 
2307     /**
2308      * If obj is non-null, reads externalizable data by invoking readExternal()


2309      * method of obj; otherwise, attempts to skip over externalizable data.
2310      * Expects that passHandle is set to obj's handle before this method is
2311      * called.

2312      */
2313     private void readExternalData(Externalizable obj, ObjectStreamClass desc)
2314         throws IOException
2315     {

















2316         SerialCallbackContext oldContext = curContext;
2317         if (oldContext != null)
2318             oldContext.check();
2319         curContext = null;
2320         try {
2321             boolean blocked = desc.hasBlockExternalData();
2322             if (blocked) {
2323                 bin.setBlockDataMode(true);
2324             }
2325             if (obj != null) {
2326                 try {
2327                     obj.readExternal(this);
2328                 } catch (ClassNotFoundException ex) {
2329                     /*
2330                      * In most cases, the handle table has already propagated
2331                      * a CNFException to passHandle at this point; this mark
2332                      * call is included to address cases where the readExternal
2333                      * method has cons'ed and thrown a new CNFException of its
2334                      * own.
2335                      */

2339             if (blocked) {
2340                 skipCustomData();
2341             }
2342         } finally {
2343             if (oldContext != null)
2344                 oldContext.check();
2345             curContext = oldContext;
2346         }
2347         /*
2348          * At this point, if the externalizable data was not written in
2349          * block-data form and either the externalizable class doesn't exist
2350          * locally (i.e., obj == null) or readExternal() just threw a
2351          * CNFException, then the stream is probably in an inconsistent state,
2352          * since some (or all) of the externalizable data may not have been
2353          * consumed.  Since there's no "correct" action to take in this case,
2354          * we mimic the behavior of past serialization implementations and
2355          * blindly hope that the stream is in sync; if it isn't and additional
2356          * externalizable data remains in the stream, a subsequent read will
2357          * most likely throw a StreamCorruptedException.
2358          */

2359     }
2360 
2361     /**
2362      * Reads and returns a record.
2363      * If an exception is marked for any of the fields, the dependency
2364      * mechanism marks the record as having an exception.
2365      * Null is returned from readRecord and later the exception is thrown at
2366      * the exit of {@link #readObject(Class)}.
2367      **/
2368     private Object readRecord(ObjectStreamClass desc) throws IOException {
2369         ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
2370         if (slots.length != 1) {

2371             // skip any superclass stream field values
2372             for (int i = 0; i < slots.length-1; i++) {
2373                 if (slots[i].hasData) {
2374                     new FieldValues(slots[i].desc, true);
2375                 }
2376             }
2377         }
2378 
2379         FieldValues fieldValues = new FieldValues(desc, true);
2380         if (handles.lookupException(passHandle) != null) {
2381             return null;     // slot marked with exception, don't create record
2382         }
2383 
2384         // get canonical record constructor adapted to take two arguments:
2385         // - byte[] primValues
2386         // - Object[] objValues
2387         // and return Object
2388         MethodHandle ctrMH = RecordSupport.deserializationCtr(desc);
2389 
2390         try {
2391             return (Object) ctrMH.invokeExact(fieldValues.primValues, fieldValues.objValues);



2392         } catch (Exception e) {
2393             throw new InvalidObjectException(e.getMessage(), e);
2394         } catch (Error e) {
2395             throw e;
2396         } catch (Throwable t) {
2397             throw new InvalidObjectException("ReflectiveOperationException " +
2398                                              "during deserialization", t);
2399         }
2400     }
2401 
2402     /**
2403      * Reads (or attempts to skip, if obj is null or is tagged with a




















































2404      * ClassNotFoundException) instance data for each serializable class of
2405      * object in stream, from superclass to subclass.  Expects that passHandle
2406      * is set to obj's handle before this method is called.
2407      */
2408     private void readSerialData(Object obj, ObjectStreamClass desc)
2409         throws IOException
2410     {
2411         ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
2412         // Best effort Failure Atomicity; slotValues will be non-null if field
2413         // values can be set after reading all field data in the hierarchy.
2414         // Field values can only be set after reading all data if there are no
2415         // user observable methods in the hierarchy, readObject(NoData). The
2416         // top most Serializable class in the hierarchy can be skipped.
2417         FieldValues[] slotValues = null;
2418 
2419         boolean hasSpecialReadMethod = false;
2420         for (int i = 1; i < slots.length; i++) {
2421             ObjectStreamClass slotDesc = slots[i].desc;
2422             if (slotDesc.hasReadObjectMethod()
2423                   || slotDesc.hasReadObjectNoDataMethod()) {
2424                 hasSpecialReadMethod = true;
2425                 break;
2426             }
2427         }
2428         // No special read methods, can store values and defer setting.
2429         if (!hasSpecialReadMethod)
2430             slotValues = new FieldValues[slots.length];
2431 
2432         for (int i = 0; i < slots.length; i++) {
2433             ObjectStreamClass slotDesc = slots[i].desc;
2434 
2435             if (slots[i].hasData) {
2436                 if (obj == null || handles.lookupException(passHandle) != null) {
2437                     // Read fields of the current descriptor into a new FieldValues and discard
2438                     new FieldValues(slotDesc, true);
2439                 } else if (slotDesc.hasReadObjectMethod()) {
2440                     SerialCallbackContext oldContext = curContext;
2441                     if (oldContext != null)
2442                         oldContext.check();
2443                     try {
2444                         curContext = new SerialCallbackContext(obj, slotDesc);
2445 
2446                         bin.setBlockDataMode(true);
2447                         slotDesc.invokeReadObject(obj, this);
2448                     } catch (ClassNotFoundException ex) {
2449                         /*
2450                          * In most cases, the handle table has already
2451                          * propagated a CNFException to passHandle at this
2452                          * point; this mark call is included to address cases
2453                          * where the custom readObject method has cons'ed and
2454                          * thrown a new CNFException of its own.
2455                          */
2456                         handles.markException(passHandle, ex);
2457                     } finally {
2458                         curContext.setUsed();
2459                         if (oldContext!= null)
2460                             oldContext.check();
2461                         curContext = oldContext;
2462                     }
2463 
2464                     /*
2465                      * defaultDataEnd may have been set indirectly by custom
2466                      * readObject() method when calling defaultReadObject() or
2467                      * readFields(); clear it to restore normal read behavior.
2468                      */
2469                     defaultDataEnd = false;

2470                 } else {
2471                     // Read fields of the current descriptor into a new FieldValues
2472                     FieldValues values = new FieldValues(slotDesc, true);
2473                     if (slotValues != null) {
2474                         slotValues[i] = values;
2475                     } else if (obj != null) {
2476                         if (handles.lookupException(passHandle) == null) {
2477                             // passHandle NOT marked with an exception; set field values
2478                             values.defaultCheckFieldValues(obj);
2479                             values.defaultSetFieldValues(obj);
2480                         }
2481                     }
2482                 }
2483 
2484                 if (slotDesc.hasWriteObjectData()) {
2485                     skipCustomData();
2486                 } else {
2487                     bin.setBlockDataMode(false);
2488                 }
2489             } else {
2490                 if (obj != null &&
2491                     slotDesc.hasReadObjectNoDataMethod() &&
2492                     handles.lookupException(passHandle) == null)
2493                 {
2494                     slotDesc.invokeReadObjectNoData(obj);
2495                 }
2496             }
2497         }


2498 
2499         if (obj != null && slotValues != null && handles.lookupException(passHandle) == null) {
2500             // passHandle NOT marked with an exception
2501             // Check that the non-primitive types are assignable for all slots
2502             // before assigning.
2503             for (int i = 0; i < slots.length; i++) {
2504                 if (slotValues[i] != null)
2505                     slotValues[i].defaultCheckFieldValues(obj);
2506             }
2507             for (int i = 0; i < slots.length; i++) {
2508                 if (slotValues[i] != null)
2509                     slotValues[i].defaultSetFieldValues(obj);



































































2510             }


2511         }
2512     }
2513 
2514     /**
2515      * Skips over all block data and objects until TC_ENDBLOCKDATA is
2516      * encountered.
2517      */
2518     private void skipCustomData() throws IOException {
2519         int oldHandle = passHandle;
2520         for (;;) {
2521             if (bin.getBlockDataMode()) {
2522                 bin.skipBlockData();
2523                 bin.setBlockDataMode(false);
2524             }
2525             switch (bin.peekByte()) {
2526                 case TC_BLOCKDATA:
2527                 case TC_BLOCKDATALONG:
2528                     bin.setBlockDataMode(true);
2529                     break;
2530 

2586     /**
2587      * Default GetField implementation.
2588      */
2589     private final class FieldValues extends GetField {
2590 
2591         /** class descriptor describing serializable fields */
2592         private final ObjectStreamClass desc;
2593         /** primitive field values */
2594         final byte[] primValues;
2595         /** object field values */
2596         final Object[] objValues;
2597         /** object field value handles */
2598         private final int[] objHandles;
2599 
2600         /**
2601          * Creates FieldValues object for reading fields defined in given
2602          * class descriptor.
2603          * @param desc the ObjectStreamClass to read
2604          * @param recordDependencies if true, record the dependencies
2605          *                           from current PassHandle and the object's read.

2606          */
2607         FieldValues(ObjectStreamClass desc, boolean recordDependencies) throws IOException {
2608             this.desc = desc;







2609 
2610             int primDataSize = desc.getPrimDataSize();
2611             primValues = (primDataSize > 0) ? new byte[primDataSize] : null;
2612             if (primDataSize > 0) {
2613                 bin.readFully(primValues, 0, primDataSize, false);
2614             }
2615 
2616             int numObjFields = desc.getNumObjFields();
2617             objValues = (numObjFields > 0) ? new Object[numObjFields] : null;
2618             objHandles = (numObjFields > 0) ? new int[numObjFields] : null;
2619             if (numObjFields > 0) {
2620                 int objHandle = passHandle;
2621                 ObjectStreamField[] fields = desc.getFields(false);
2622                 int numPrimFields = fields.length - objValues.length;
2623                 for (int i = 0; i < objValues.length; i++) {
2624                     ObjectStreamField f = fields[numPrimFields + i];
2625                     objValues[i] = readObject0(Object.class, f.isUnshared());
2626                     objHandles[i] = passHandle;
2627                     if (recordDependencies && f.getField() != null) {
2628                         handles.markDependency(objHandle, passHandle);

2629                     }

2630                 }
2631                 passHandle = objHandle;

2632             }
2633         }
2634 
2635         public ObjectStreamClass getObjectStreamClass() {
2636             return desc;
2637         }
2638 
2639         public boolean defaulted(String name) {
2640             return (getFieldOffset(name, null) < 0);
2641         }
2642 
2643         public boolean get(String name, boolean val) {
2644             int off = getFieldOffset(name, Boolean.TYPE);
2645             return (off >= 0) ? ByteArray.getBoolean(primValues, off) : val;
2646         }
2647 
2648         public byte get(String name, byte val) {
2649             int off = getFieldOffset(name, Byte.TYPE);
2650             return (off >= 0) ? primValues[off] : val;
2651         }

   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.io;
  27 
  28 import java.io.ObjectInputFilter.Config;
  29 import java.io.ObjectStreamClass.ConstructorSupport;
  30 import java.io.ObjectStreamClass.ClassDataSlot;
  31 import java.lang.System.Logger;
  32 import java.lang.invoke.MethodHandle;
  33 import java.lang.reflect.Array;
  34 import java.lang.reflect.InvocationHandler;
  35 import java.lang.reflect.InvocationTargetException;
  36 import java.lang.reflect.Modifier;
  37 import java.lang.reflect.Proxy;
  38 import java.nio.charset.StandardCharsets;
  39 import java.security.AccessControlContext;
  40 import java.security.AccessController;
  41 import java.security.PrivilegedAction;
  42 import java.security.PrivilegedActionException;
  43 import java.security.PrivilegedExceptionAction;
  44 import java.util.Arrays;
  45 import java.util.List;
  46 import java.util.Locale;
  47 import java.util.Objects;
  48 
  49 import jdk.internal.access.JavaLangAccess;
  50 import jdk.internal.access.SharedSecrets;
  51 import jdk.internal.event.DeserializationEvent;
  52 import jdk.internal.misc.Unsafe;
  53 import jdk.internal.util.ByteArray;
  54 import sun.reflect.misc.ReflectUtil;
  55 import sun.security.action.GetBooleanAction;
  56 import sun.security.action.GetIntegerAction;
  57 import sun.security.action.GetPropertyAction;
  58 
  59 /**
  60  * An ObjectInputStream deserializes primitive data and objects previously
  61  * written using an ObjectOutputStream.
  62  *
  63  * <p><strong>Warning: Deserialization of untrusted data is inherently dangerous
  64  * and should be avoided. Untrusted data should be carefully validated according to the
  65  * "Serialization and Deserialization" section of the
  66  * {@extLink secure_coding_guidelines_javase Secure Coding Guidelines for Java SE}.
  67  * {@extLink serialization_filter_guide Serialization Filtering} describes best
  68  * practices for defensive use of serial filters.
  69  * </strong></p>
  70  *
  71  * <p>The key to disabling deserialization attacks is to prevent instances of
  72  * arbitrary classes from being deserialized, thereby preventing the direct or
  73  * indirect execution of their methods.
  74  * {@link ObjectInputFilter} describes how to use filters and
  75  * {@link ObjectInputFilter.Config} describes how to configure the filter and filter factory.
  76  * Each stream has an optional deserialization filter
  77  * to check the classes and resource limits during deserialization.

 206  * <p>Serialization does not read or assign values to the fields of any object
 207  * that does not implement the java.io.Serializable interface.  Subclasses of
 208  * Objects that are not serializable can be serializable. In this case the
 209  * non-serializable class must have a no-arg constructor to allow its fields to
 210  * be initialized.  In this case it is the responsibility of the subclass to
 211  * save and restore the state of the non-serializable class. It is frequently
 212  * the case that the fields of that class are accessible (public, package, or
 213  * protected) or that there are get and set methods that can be used to restore
 214  * the state.
 215  *
 216  * <p>Any exception that occurs while deserializing an object will be caught by
 217  * the ObjectInputStream and abort the reading process.
 218  *
 219  * <p>Implementing the Externalizable interface allows the object to assume
 220  * complete control over the contents and format of the object's serialized
 221  * form.  The methods of the Externalizable interface, writeExternal and
 222  * readExternal, are called to save and restore the objects state.  When
 223  * implemented by a class they can write and read their own state using all of
 224  * the methods of ObjectOutput and ObjectInput.  It is the responsibility of
 225  * the objects to handle any versioning that occurs.
 226  * Value objects cannot be `java.io.Externalizable` because value objects are
 227  * immutable and `Externalizable.readExternal` is unable to modify the fields of the value.
 228  *
 229  * <p>Enum constants are deserialized differently than ordinary serializable or
 230  * externalizable objects.  The serialized form of an enum constant consists
 231  * solely of its name; field values of the constant are not transmitted.  To
 232  * deserialize an enum constant, ObjectInputStream reads the constant name from
 233  * the stream; the deserialized constant is then obtained by calling the static
 234  * method {@code Enum.valueOf(Class, String)} with the enum constant's
 235  * base type and the received constant name as arguments.  Like other
 236  * serializable or externalizable objects, enum constants can function as the
 237  * targets of back references appearing subsequently in the serialization
 238  * stream.  The process by which enum constants are deserialized cannot be
 239  * customized: any class-specific readObject, readObjectNoData, and readResolve
 240  * methods defined by enum types are ignored during deserialization.
 241  * Similarly, any serialPersistentFields or serialVersionUID field declarations
 242  * are also ignored--all enum types have a fixed serialVersionUID of 0L.
 243  *
 244  * <a id="record-serialization"></a>
 245  * <p>Records are serialized differently than ordinary serializable or externalizable
 246  * objects. During deserialization the record's canonical constructor is invoked
 247  * to construct the record object. Certain serialization-related methods, such
 248  * as readObject and writeObject, are ignored for serializable records. See
 249  * <a href="{@docRoot}/../specs/serialization/serial-arch.html#serialization-of-records">
 250  * <cite>Java Object Serialization Specification,</cite> Section 1.13,
 251  * "Serialization of Records"</a> for additional information.
 252  *
 253  * <p>Value classes are {@linkplain Serializable} through the use of the serialization proxy pattern.
 254  * See {@linkplain ObjectOutputStream##valueclass-serialization value class serialization} for details.
 255  * When the proxy is deserialized it re-constructs and returns the value object.
 256  *
 257  * @spec serialization/index.html Java Object Serialization Specification
 258  * @author      Mike Warres
 259  * @author      Roger Riggs
 260  * @see java.io.DataInput
 261  * @see java.io.ObjectOutputStream
 262  * @see java.io.Serializable
 263  * @see <a href="{@docRoot}/../specs/serialization/input.html">
 264  *      <cite>Java Object Serialization Specification,</cite> Section 3, "Object Input Classes"</a>
 265  * @since   1.1
 266  */
 267 public class ObjectInputStream
 268     extends InputStream implements ObjectInput, ObjectStreamConstants
 269 {
 270     private static final String TRACE_DEST =
 271             GetPropertyAction.privilegedGetProperty("TRACE");
 272 
 273     static void TRACE(String format, Object... args) {
 274         if (TRACE_DEST != null) {
 275             var ps = "OUT".equals(TRACE_DEST.toUpperCase(Locale.ROOT)) ? System.out : System.err;
 276             ps.println(("TRACE " + format).formatted(args));
 277         }
 278     }
 279 
 280     /** handle value representing null */
 281     private static final int NULL_HANDLE = -1;
 282 
 283     /** marker for unshared objects in internal handle table */
 284     private static final Object unsharedMarker = new Object();
 285 
 286     private static class Caches {
 287         /** cache of subclass security audit results */
 288         static final ClassValue<Boolean> subclassAudits =
 289             new ClassValue<>() {
 290                 @Override
 291                 protected Boolean computeValue(Class<?> type) {
 292                     return auditSubclass(type);
 293                 }
 294             };
 295 
 296         /**
 297          * Property to permit setting a filter after objects
 298          * have been read.
 299          * See {@link #setObjectInputFilter(ObjectInputFilter)}

 469 
 470     /**
 471      * Read an object from the ObjectInputStream.  The class of the object, the
 472      * signature of the class, and the values of the non-transient and
 473      * non-static fields of the class and all of its supertypes are read.
 474      * Default deserializing for a class can be overridden using the writeObject
 475      * and readObject methods.  Objects referenced by this object are read
 476      * transitively so that a complete equivalent graph of objects is
 477      * reconstructed by readObject.
 478      *
 479      * <p>The root object is completely restored when all of its fields and the
 480      * objects it references are completely restored.  At this point the object
 481      * validation callbacks are executed in order based on their registered
 482      * priorities. The callbacks are registered by objects (in the readObject
 483      * special methods) as they are individually restored.
 484      *
 485      * <p>The deserialization filter, when not {@code null}, is invoked for
 486      * each object (regular or class) read to reconstruct the root object.
 487      * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
 488      *
 489      * <p>Serialization and deserialization of value classes is described in
 490      * {@linkplain ObjectOutputStream##valueclass-serialization value class serialization}.
 491      *
 492      * @implSpec
 493      * When enabled with {@code --enable-preview}, serialization and deserialization of
 494      * Core Library value classes migrated from pre-JEP 401 identity classes is
 495      * implementation specific.
 496      *
 497      * <p>Exceptions are thrown for problems with the InputStream and for
 498      * classes that should not be deserialized.  All exceptions are fatal to
 499      * the InputStream and leave it in an indeterminate state; it is up to the
 500      * caller to ignore or recover the stream state.
 501      *
 502      * @throws  ClassNotFoundException Class of a serialized object cannot be
 503      *          found.
 504      * @throws  InvalidClassException Something is wrong with a class used by
 505      *          deserialization.
 506      * @throws  StreamCorruptedException Control information in the
 507      *          stream is inconsistent.
 508      * @throws  OptionalDataException Primitive data was found in the
 509      *          stream instead of objects.
 510      * @throws  IOException Any of the usual Input/Output related exceptions.
 511      */
 512     public final Object readObject()
 513         throws IOException, ClassNotFoundException {
 514         return readObject(Object.class);
 515     }
 516 

 610      *       to deserialize back-references to the stream handle deserialized
 611      *       by readUnshared will cause an ObjectStreamException to be thrown.
 612      * </ul>
 613      * Deserializing an object via readUnshared invalidates the stream handle
 614      * associated with the returned object.  Note that this in itself does not
 615      * always guarantee that the reference returned by readUnshared is unique;
 616      * the deserialized object may define a readResolve method which returns an
 617      * object visible to other parties, or readUnshared may return a Class
 618      * object or enum constant obtainable elsewhere in the stream or through
 619      * external means. If the deserialized object defines a readResolve method
 620      * and the invocation of that method returns an array, then readUnshared
 621      * returns a shallow clone of that array; this guarantees that the returned
 622      * array object is unique and cannot be obtained a second time from an
 623      * invocation of readObject or readUnshared on the ObjectInputStream,
 624      * even if the underlying data stream has been manipulated.
 625      *
 626      * <p>The deserialization filter, when not {@code null}, is invoked for
 627      * each object (regular or class) read to reconstruct the root object.
 628      * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
 629      *
 630      * <p>Serialization and deserialization of value classes is described in
 631      * {@linkplain ObjectOutputStream##valueclass-serialization value class serialization}.
 632      *
 633      * <p>ObjectInputStream subclasses which override this method can only be
 634      * constructed in security contexts possessing the
 635      * "enableSubclassImplementation" SerializablePermission; any attempt to
 636      * instantiate such a subclass without this permission will cause a
 637      * SecurityException to be thrown.
 638      *
 639      * @return  reference to deserialized object
 640      * @throws  ClassNotFoundException if class of an object to deserialize
 641      *          cannot be found
 642      * @throws  StreamCorruptedException if control information in the stream
 643      *          is inconsistent
 644      * @throws  ObjectStreamException if object to deserialize has already
 645      *          appeared in stream
 646      * @throws  OptionalDataException if primitive data is next in stream
 647      * @throws  IOException if an I/O error occurs during deserialization
 648      * @since   1.4
 649      */
 650     public Object readUnshared() throws IOException, ClassNotFoundException {
 651         // if nested read, passHandle contains handle of enclosing object
 652         int outerHandle = passHandle;

2266      * class is unresolvable (in which case a ClassNotFoundException will be
2267      * associated with object's handle).  Sets passHandle to object's assigned
2268      * handle.
2269      */
2270     private Object readOrdinaryObject(boolean unshared)
2271         throws IOException
2272     {
2273         if (bin.readByte() != TC_OBJECT) {
2274             throw new InternalError();
2275         }
2276 
2277         ObjectStreamClass desc = readClassDesc(false);
2278         desc.checkDeserialize();
2279 
2280         Class<?> cl = desc.forClass();
2281         if (cl == String.class || cl == Class.class
2282                 || cl == ObjectStreamClass.class) {
2283             throw new InvalidClassException("invalid class descriptor");
2284         }
2285 
2286         // Assign the handle and initially set to null or the unsharedMarker
2287         passHandle = handles.assign(unshared ? unsharedMarker : null);







2288         ClassNotFoundException resolveEx = desc.getResolveException();
2289         if (resolveEx != null) {
2290             handles.markException(passHandle, resolveEx);
2291         }
2292 
2293         try {
2294             // Dispatch on the factory mode to read an object from the stream.
2295             Object obj = switch (desc.factoryMode()) {
2296                 case READ_OBJECT_DEFAULT -> readSerialDefaultObject(desc, unshared);
2297                 case READ_OBJECT_CUSTOM -> readSerialCustomData(desc, unshared);
2298                 case READ_RECORD -> readRecord(desc, unshared);
2299                 case READ_EXTERNALIZABLE -> readExternalObject(desc, unshared);
2300                 case READ_OBJECT_VALUE -> readObjectValue(desc, unshared);
2301                 case READ_NO_LOCAL_CLASS -> readAbsentLocalClass(desc, unshared);
2302                 case null -> throw new AssertionError("Unknown factoryMode for: " + desc.getName(),
2303                         resolveEx);
2304             };
2305 
2306             handles.finish(passHandle);
2307 
2308             if (obj != null &&
2309                 handles.lookupException(passHandle) == null &&
2310                 desc.hasReadResolveMethod())
2311             {
2312                 Object rep = desc.invokeReadResolve(obj);
2313                 if (unshared && rep.getClass().isArray()) {
2314                     rep = cloneArray(rep);
2315                 }
2316                 if (rep != obj) {
2317                     // Filter the replacement object
2318                     if (rep != null) {
2319                         if (rep.getClass().isArray()) {
2320                             filterCheck(rep.getClass(), Array.getLength(rep));
2321                         } else {
2322                             filterCheck(rep.getClass(), -1);
2323                         }
2324                     }
2325                     handles.setObject(passHandle, obj = rep);
2326                 }
2327             }
2328 
2329             return obj;
2330         } catch (UncheckedIOException uioe) {
2331             // Consistent re-throw for nested UncheckedIOExceptions
2332             throw uioe.getCause();
2333         }
2334     }
2335 
2336     /**
2337      * {@return a value class instance by invoking its constructor with field values read from the stream.
2338      * The fields of the class in the stream are matched to the local fields and applied to
2339      * the constructor.
2340      * If the stream contains superclasses with serializable fields,
2341      * an InvalidClassException is thrown with an incompatible class change message.
2342      *
2343      * @param desc the class descriptor read from the stream, the local class is a value class
2344      * @param unshared if the object is not to be shared
2345      * @throws InvalidClassException if the stream contains a superclass with serializable fields.
2346      * @throws IOException if there are I/O errors while reading from the
2347      *         underlying {@code InputStream}
2348      */
2349     private Object readObjectValue(ObjectStreamClass desc, boolean unshared) throws IOException {
2350         final ObjectStreamClass localDesc = desc.getLocalDesc();
2351         TRACE("readObjectValue: %s, local class: %s", desc.getName(), localDesc.getName());
2352         // Check for un-expected fields in superclasses
2353         List<ClassDataSlot> slots = desc.getClassDataLayout();
2354         for (int i = 0; i < slots.size()-1; i++) {
2355             ClassDataSlot slot = slots.get(i);
2356             if (slot.hasData && slot.desc.getFields(false).length > 0) {
2357                 throw new InvalidClassException("incompatible class change to value class: " +
2358                         "stream class has non-empty super type: " + desc.getName());
2359             }
2360         }
2361         // Read values for the value class fields
2362         FieldValues fieldValues = new FieldValues(desc, true);
2363 
2364         // Get value object constructor adapted to take primitive value buffer and object array.
2365         MethodHandle consMH = ConstructorSupport.deserializationValueCons(desc);
2366         try {
2367             Object obj = (Object) consMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
2368             if (!unshared)
2369                 handles.setObject(passHandle, obj);
2370             return obj;
2371         } catch (Exception e) {
2372             throw new InvalidObjectException(e.getMessage(), e);
2373         } catch (Error e) {
2374             throw e;
2375         } catch (Throwable t) {
2376             throw new InvalidObjectException("ReflectiveOperationException " +
2377                     "during deserialization", t);
2378         }
2379     }
2380 
2381     /**
2382      * Creates a new object and invokes its readExternal method to read its contents.
2383      *
2384      * If the class is instantiable, read externalizable data by invoking readExternal()
2385      * method of obj; otherwise, attempts to skip over externalizable data.
2386      * Expects that passHandle is set to obj's handle before this method is
2387      * called.  The new object is entered in the handle table immediately,
2388      * allowing it to leak before it is completely read.
2389      */
2390     private Object readExternalObject(ObjectStreamClass desc, boolean unshared)
2391         throws IOException
2392     {
2393         TRACE("readExternalObject: %s", desc.getName());
2394 
2395         // For Externalizable objects,
2396         // create the instance, publish the ref, and read the data
2397         Externalizable obj = null;
2398         try {
2399             if (desc.isInstantiable()) {
2400                 obj = (Externalizable) desc.newInstance();
2401             }
2402         } catch (Exception ex) {
2403             throw new InvalidClassException(desc.getName(),
2404                     "unable to create instance", ex);
2405         }
2406 
2407         if (!unshared)
2408             handles.setObject(passHandle, obj);
2409 
2410         SerialCallbackContext oldContext = curContext;
2411         if (oldContext != null)
2412             oldContext.check();
2413         curContext = null;
2414         try {
2415             boolean blocked = desc.hasBlockExternalData();
2416             if (blocked) {
2417                 bin.setBlockDataMode(true);
2418             }
2419             if (obj != null) {
2420                 try {
2421                     obj.readExternal(this);
2422                 } catch (ClassNotFoundException ex) {
2423                     /*
2424                      * In most cases, the handle table has already propagated
2425                      * a CNFException to passHandle at this point; this mark
2426                      * call is included to address cases where the readExternal
2427                      * method has cons'ed and thrown a new CNFException of its
2428                      * own.
2429                      */

2433             if (blocked) {
2434                 skipCustomData();
2435             }
2436         } finally {
2437             if (oldContext != null)
2438                 oldContext.check();
2439             curContext = oldContext;
2440         }
2441         /*
2442          * At this point, if the externalizable data was not written in
2443          * block-data form and either the externalizable class doesn't exist
2444          * locally (i.e., obj == null) or readExternal() just threw a
2445          * CNFException, then the stream is probably in an inconsistent state,
2446          * since some (or all) of the externalizable data may not have been
2447          * consumed.  Since there's no "correct" action to take in this case,
2448          * we mimic the behavior of past serialization implementations and
2449          * blindly hope that the stream is in sync; if it isn't and additional
2450          * externalizable data remains in the stream, a subsequent read will
2451          * most likely throw a StreamCorruptedException.
2452          */
2453         return obj;
2454     }
2455 
2456     /**
2457      * Reads and returns a record.
2458      * If an exception is marked for any of the fields, the dependency
2459      * mechanism marks the record as having an exception.
2460      * Null is returned from readRecord and later the exception is thrown at
2461      * the exit of {@link #readObject(Class)}.
2462      */
2463     private Object readRecord(ObjectStreamClass desc, boolean unshared) throws IOException {
2464         TRACE("invoking readRecord: %s", desc.getName());
2465         List<ClassDataSlot> slots = desc.getClassDataLayout();
2466         if (slots.size() != 1) {
2467             // skip any superclass stream field values
2468             for (int i = 0; i < slots.size()-1; i++) {
2469                 if (slots.get(i).hasData) {
2470                     new FieldValues(slots.get(i).desc, true);
2471                 }
2472             }
2473         }
2474 
2475         FieldValues fieldValues = new FieldValues(desc, true);
2476         if (handles.lookupException(passHandle) != null) {
2477             return null;     // slot marked with exception, don't create record
2478         }
2479 
2480         // get canonical record constructor adapted to take two arguments:
2481         // - byte[] primValues
2482         // - Object[] objValues
2483         // and return Object
2484         MethodHandle ctrMH = ConstructorSupport.deserializationCtr(desc);
2485 
2486         try {
2487             Object obj = (Object) ctrMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
2488             if (!unshared)
2489                 handles.setObject(passHandle, obj);
2490             return obj;
2491         } catch (Exception e) {
2492             throw new InvalidObjectException(e.getMessage(), e);
2493         } catch (Error e) {
2494             throw e;
2495         } catch (Throwable t) {
2496             throw new InvalidObjectException("ReflectiveOperationException " +
2497                                              "during deserialization", t);
2498         }
2499     }
2500 
2501     /**
2502      * Construct an object from the stream for a class that has only default read object behaviors.
2503      * For each object, the fields are read before any are assigned.
2504      * The new instance is entered in the handle table if it is unshared,
2505      * allowing it to escape before it is initialized.
2506      * The `readObject` and `readObjectNoData` methods are not present and are not called.
2507      *
2508      * @param desc the class descriptor
2509      * @param unshared true if the object should be shared
2510      * @return the object constructed from the stream data
2511      * @throws IOException if there are I/O errors while reading from the
2512      *         underlying {@code InputStream}
2513      * @throws InvalidClassException if the instance creation fails
2514      */
2515     private Object readSerialDefaultObject(ObjectStreamClass desc, boolean unshared)
2516             throws IOException, InvalidClassException {
2517         if (!desc.isInstantiable()) {
2518             // No local class to create, read and discard
2519             return readAbsentLocalClass(desc, unshared);
2520         }
2521         TRACE("readSerialDefaultObject: %s", desc.getName());
2522         try {
2523             final Object obj = desc.newInstance();
2524             if (!unshared)
2525                 handles.setObject(passHandle, obj);
2526 
2527             // Best effort Failure Atomicity; slotValues will be non-null if field
2528             // values can be set after reading all field data in the hierarchy.
2529             List<FieldValues> slotValues = desc.getClassDataLayout().stream()
2530                     .filter(s -> s.hasData)
2531                     .map(s1 -> {
2532                         var values = new FieldValues(s1.desc, true);
2533                         finishBlockData(s1.desc);
2534                         return values;
2535                     })
2536                     .toList();
2537 
2538             if (handles.lookupException(passHandle) != null) {
2539                 return null;    // some exception for a class, do not return the object
2540             }
2541 
2542             // Check that the types are assignable for all slots before assigning.
2543             slotValues.forEach(v -> v.defaultCheckFieldValues(obj));
2544             slotValues.forEach(v -> v.defaultSetFieldValues(obj));
2545             return obj;
2546         } catch (InstantiationException | InvocationTargetException ex) {
2547             throw new InvalidClassException(desc.forClass().getName(),
2548                     "unable to create instance", ex);
2549         }
2550     }
2551 
2552 
2553     /**
2554      * Reads (or attempts to skip, if not instantiatable or is tagged with a
2555      * ClassNotFoundException) instance data for each serializable class of
2556      * object in stream, from superclass to subclass.
2557      * Expects that passHandle is set to current handle before this method is called.
2558      */
2559     private Object readSerialCustomData(ObjectStreamClass desc, boolean unshared)
2560         throws IOException
2561     {
2562         if (!desc.isInstantiable()) {
2563             // No local class to create, read and discard
2564             return readAbsentLocalClass(desc, unshared);













2565         }



2566 
2567         TRACE("readSerialCustomData: %s, ex: %s", desc.getName(), handles.lookupException(passHandle));
2568         try {
2569             Object obj = desc.newInstance();
2570             if (!unshared)
2571                 handles.setObject(passHandle, obj);
2572             // Read data into each of the slots for the class
2573             return readSerialCustomSlots(obj, desc.getClassDataLayout());
2574         } catch (InstantiationException | InvocationTargetException ex) {
2575             throw new InvalidClassException(desc.forClass().getName(),
2576                     "unable to create instance", ex);
2577         }
2578     }

2579 
2580     /**
2581      * Reads from the stream using custom or default readObject methods appropriate.
2582      * For each slot, either the custom readObject method or the default reader of fields
2583      * is invoked. Unused slot specific custom data is discarded.
2584      * This function is used by {@link #readSerialCustomData}.
2585      *
2586      * @param obj the object to assign the values to
2587      * @param slots a list of slots to read from the stream
2588      * @return the object being initialized
2589      * @throws IOException if there are I/O errors while reading from the
2590      *         underlying {@code InputStream}
2591      */
2592     private Object readSerialCustomSlots(Object obj, List<ClassDataSlot> slots) throws IOException {
2593         TRACE("    readSerialCustomSlots: %s", slots);



2594 
2595         for (ClassDataSlot slot : slots) {
2596             ObjectStreamClass slotDesc = slot.desc;
2597             if (slot.hasData) {
2598                 if (slotDesc.hasReadObjectMethod() &&
2599                         handles.lookupException(passHandle) == null) {
2600                     // Invoke slot custom readObject method
2601                     readSlotViaReadObject(obj, slotDesc);
2602                 } else {
2603                     // Read fields of the current descriptor into a new FieldValues
2604                     FieldValues values = new FieldValues(slotDesc, true);
2605                     if (handles.lookupException(passHandle) == null) {
2606                         // Set the instance fields if no previous exception
2607                         values.defaultCheckFieldValues(obj);
2608                         values.defaultSetFieldValues(obj);




2609                     }
2610                     finishBlockData(slotDesc);





2611                 }
2612             } else {
2613                 if (slotDesc.hasReadObjectNoDataMethod() &&
2614                         handles.lookupException(passHandle) == null) {


2615                     slotDesc.invokeReadObjectNoData(obj);
2616                 }
2617             }
2618         }
2619         return obj;
2620     }
2621 
2622     /**
2623      * Invoke the readObject method of the class to read and store the state from the stream.
2624      *
2625      * @param obj an instance of the class being created, only partially initialized.
2626      * @param slotDesc the ObjectStreamDescriptor for the current class
2627      * @throws IOException if there are I/O errors while reading from the
2628      *         underlying {@code InputStream}
2629      */
2630     private void readSlotViaReadObject(Object obj, ObjectStreamClass slotDesc) throws IOException {
2631         TRACE("readSlotViaReadObject: %s", slotDesc.getName());
2632         assert obj != null : "readSlotViaReadObject called when obj == null";
2633 
2634         SerialCallbackContext oldContext = curContext;
2635         if (oldContext != null)
2636             oldContext.check();
2637         try {
2638             curContext = new SerialCallbackContext(obj, slotDesc);
2639 
2640             bin.setBlockDataMode(true);
2641             slotDesc.invokeReadObject(obj, this);
2642         } catch (ClassNotFoundException ex) {
2643             /*
2644              * In most cases, the handle table has already
2645              * propagated a CNFException to passHandle at this
2646              * point; this mark call is included to address cases
2647              * where the custom readObject method has cons'ed and
2648              * thrown a new CNFException of its own.
2649              */
2650             handles.markException(passHandle, ex);
2651         } finally {
2652             curContext.setUsed();
2653             if (oldContext!= null)
2654                 oldContext.check();
2655             curContext = oldContext;
2656         }
2657 
2658         /*
2659          * defaultDataEnd may have been set indirectly by custom
2660          * readObject() method when calling defaultReadObject() or
2661          * readFields(); clear it to restore normal read behavior.
2662          */
2663         defaultDataEnd = false;
2664 
2665         finishBlockData(slotDesc);
2666     }
2667 
2668 
2669     /**
2670      * Read and discard an entire object, leaving a null reference in the HandleTable.
2671      * The descriptor of the class in the stream is used to read the fields from the stream.
2672      * There is no instance in which to store the field values.
2673      * Custom data following the fields of any slot is read and discarded.
2674      * References to nested objects are read and retained in the
2675      * handle table using the regular mechanism.
2676      * Handles later in the stream may refer to the nested objects.
2677      *
2678      * @param desc the stream class descriptor
2679      * @param unshared the unshared flag, ignored since no object is created
2680      * @return null, no object is created
2681      * @throws IOException if there are I/O errors while reading from the
2682      *         underlying {@code InputStream}
2683      */
2684     private Object readAbsentLocalClass(ObjectStreamClass desc, boolean unshared)
2685             throws IOException {
2686         TRACE("readAbsentLocalClass: %s", desc.getName());
2687         desc.getClassDataLayout().stream()
2688                 .filter(s -> s.hasData)
2689                 .forEach(s2 -> {new FieldValues(s2.desc, true); finishBlockData(s2.desc);});
2690         return null;
2691     }
2692 
2693     // Finish handling of block data by skipping any remaining and setting BlockDataMode = false
2694     private void finishBlockData(ObjectStreamClass slotDesc) throws UncheckedIOException {
2695         try {
2696             if (slotDesc.hasWriteObjectData()) {
2697                 skipCustomData();
2698             } else {
2699                 bin.setBlockDataMode(false);
2700             }
2701         } catch (IOException ioe) {
2702             throw new UncheckedIOException(ioe);
2703         }
2704     }
2705 
2706     /**
2707      * Skips over all block data and objects until TC_ENDBLOCKDATA is
2708      * encountered.
2709      */
2710     private void skipCustomData() throws IOException {
2711         int oldHandle = passHandle;
2712         for (;;) {
2713             if (bin.getBlockDataMode()) {
2714                 bin.skipBlockData();
2715                 bin.setBlockDataMode(false);
2716             }
2717             switch (bin.peekByte()) {
2718                 case TC_BLOCKDATA:
2719                 case TC_BLOCKDATALONG:
2720                     bin.setBlockDataMode(true);
2721                     break;
2722 

2778     /**
2779      * Default GetField implementation.
2780      */
2781     private final class FieldValues extends GetField {
2782 
2783         /** class descriptor describing serializable fields */
2784         private final ObjectStreamClass desc;
2785         /** primitive field values */
2786         final byte[] primValues;
2787         /** object field values */
2788         final Object[] objValues;
2789         /** object field value handles */
2790         private final int[] objHandles;
2791 
2792         /**
2793          * Creates FieldValues object for reading fields defined in given
2794          * class descriptor.
2795          * @param desc the ObjectStreamClass to read
2796          * @param recordDependencies if true, record the dependencies
2797          *                           from current PassHandle and the object's read.
2798          * @throws UncheckedIOException if any IOException occurs
2799          */
2800         FieldValues(ObjectStreamClass desc, boolean recordDependencies) throws UncheckedIOException {
2801             try {
2802                 this.desc = desc;
2803                 TRACE("    reading FieldValues: %s", desc.getName());
2804                 int primDataSize = desc.getPrimDataSize();
2805                 primValues = (primDataSize > 0) ? new byte[primDataSize] : null;
2806                 if (primDataSize > 0) {
2807                     bin.readFully(primValues, 0, primDataSize, false);
2808                 }
2809 





2810 
2811                 int numObjFields = desc.getNumObjFields();
2812                 objValues = (numObjFields > 0) ? new Object[numObjFields] : null;
2813                 objHandles = (numObjFields > 0) ? new int[numObjFields] : null;
2814                 if (numObjFields > 0) {
2815                     int objHandle = passHandle;
2816                     ObjectStreamField[] fields = desc.getFields(false);
2817                     int numPrimFields = fields.length - objValues.length;
2818                     for (int i = 0; i < objValues.length; i++) {
2819                         ObjectStreamField f = fields[numPrimFields + i];
2820                         objValues[i] = readObject0(Object.class, f.isUnshared());
2821                         objHandles[i] = passHandle;
2822                         if (recordDependencies && f.getField() != null) {
2823                             handles.markDependency(objHandle, passHandle);
2824                         }
2825                     }
2826                     passHandle = objHandle;
2827                 }
2828             } catch (IOException ioe) {
2829                 throw new UncheckedIOException(ioe);
2830             }
2831         }
2832 
2833         public ObjectStreamClass getObjectStreamClass() {
2834             return desc;
2835         }
2836 
2837         public boolean defaulted(String name) {
2838             return (getFieldOffset(name, null) < 0);
2839         }
2840 
2841         public boolean get(String name, boolean val) {
2842             int off = getFieldOffset(name, Boolean.TYPE);
2843             return (off >= 0) ? ByteArray.getBoolean(primValues, off) : val;
2844         }
2845 
2846         public byte get(String name, byte val) {
2847             int off = getFieldOffset(name, Byte.TYPE);
2848             return (off >= 0) ? primValues[off] : val;
2849         }
< prev index next >