/******************* * Handle a string element. * * @param obj The RMIObject to populate with class names. ******************/ private void handleStringElement(LinkedList<Byte> dataStack) throws BaRMIeInvalidReplyDataPacketException { //Handle a string based on the type switch(dataStack.pop()) { //Standard string case ObjectStreamConstants.TC_STRING: this.extractUtf8(dataStack); break; //Long string case ObjectStreamConstants.TC_LONGSTRING: this.extractLongUtf8(dataStack); break; //References case ObjectStreamConstants.TC_REFERENCE: this.extractInt(dataStack); break; //Invalid string type default: throw new BaRMIeInvalidReplyDataPacketException("Invalid string element type."); } }
public E readObject() throws ClassNotFoundException, IOException { int b = peek(); if (b == ObjectStreamConstants.TC_NULL) { return null; } else { E obj; try { obj = type.newInstance(); obj.readExternal(this); return obj; } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } }
public List<Content> read_classAnnotation( DataInputStream dis ) throws IOException { List<Content> list = new ArrayList<Content>(); while ( true ) { byte tc = dis.readByte(); if ( tc == ObjectStreamConstants.TC_ENDBLOCKDATA ) { return list; } if ( tc == ObjectStreamConstants.TC_RESET ) { reset(); continue; } Content c = read_Content( tc, dis, true ); if ( c != null && c.isExceptionObject() ) { throw new ReadException( c ); } list.add( c ); } }
/** * Read the content of a thrown exception object. According to the spec, this must be * an object of type Throwable. Although the Sun JDK always appears to provide enough * information about the hierarchy to reach all the way back to java.lang.Throwable, * it's unclear whether this is actually a requirement. From my reading, it's * possible that some other ObjectOutputStream implementations may leave some gaps in * the hierarchy, forcing this app to hit the classloader. To avoid this, we merely * ensure that the written object is indeed an instance; ensuring that the object is * indeed a Throwable is an exercise left to the user. */ public Content read_Exception( DataInputStream dis ) throws IOException { reset(); byte tc = dis.readByte(); if ( tc == ObjectStreamConstants.TC_RESET ) { throw new ValidityException( "TC_RESET for object while reading exception: what should we do?" ); } Content c = read_Content( tc, dis, false ); if ( c == null ) { throw new ValidityException( "stream signaled for an exception, but exception object was null!" ); } if ( !( c instanceof Instance ) ) { throw new ValidityException( "stream signaled for an exception, but content is not an object!" ); } if ( c.isExceptionObject() ) { throw new ReadException( c ); } c.setIsExceptionObject( true ); reset(); return c; }
public BlockData read_blockdata( byte tc, DataInputStream dis ) throws IOException { int size; if ( tc == ObjectStreamConstants.TC_BLOCKDATA ) { size = dis.readUnsignedByte(); } else if ( tc == ObjectStreamConstants.TC_BLOCKDATALONG ) { size = dis.readInt(); } else { throw new IOException( "invalid tc value for blockdata: " + hex( tc ) ); } if ( size < 0 ) { throw new IOException( "invalid value for blockdata size: " + size ); } byte[] b = new byte[size]; dis.readFully( b ); debug( "read blockdata of size " + size ); return new BlockData( b ); }
public void validate() throws ValidityException { // If neither SC_SERIALIZABLE nor SC_EXTERNALIZABLE is set, then the number of // fields is always zero. (spec section 4.3) if ( ( descflags & ( ObjectStreamConstants.SC_SERIALIZABLE | ObjectStreamConstants.SC_EXTERNALIZABLE ) ) == 0 && fields != null && fields.length > 0 ) { throw new ValidityException( "non-serializable, non-externalizable class has fields!" ); } if ( ( descflags & ( ObjectStreamConstants.SC_SERIALIZABLE | ObjectStreamConstants.SC_EXTERNALIZABLE ) ) == ( ObjectStreamConstants.SC_SERIALIZABLE | ObjectStreamConstants.SC_EXTERNALIZABLE ) ) { throw new ValidityException( "both Serializable and Externalizable are set!" ); } if ( ( descflags & ObjectStreamConstants.SC_ENUM ) != 0 ) { // we're an enum; shouldn't have any fields/superinterfaces if ( ( fields != null && fields.length > 0 ) || interfaces != null ) { throw new ValidityException( "enums shouldn't implement interfaces or have non-constant fields!" ); } } else { // non-enums shouldn't have enum constant fields. if ( enumconstants != null && enumconstants.size() > 0 ) { throw new ValidityException( "non-enum classes shouldn't have enum constants!" ); } } }
private static void initialize() { try { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); DataOutputStream dout = new DataOutputStream(byteOut); dout.writeShort(ObjectStreamConstants.STREAM_MAGIC); dout.writeShort(ObjectStreamConstants.STREAM_VERSION); HEADER = byteOut.toByteArray(); byteOut = new ByteArrayOutputStream(); dout = new DataOutputStream(byteOut); dout.writeByte(ObjectStreamConstants.TC_OBJECT); dout.writeByte(ObjectStreamConstants.TC_REFERENCE); dout.writeInt(ObjectStreamConstants.baseWireHandle); REPEATING_DATA = byteOut.toByteArray(); } catch(IOException e) { throw new Error("IOException: " + e.getMessage()); } }
/******************* * Handle a classDesc element. * * @param obj The RMIObject to populate with class names. * @param dataStack The remaining data in the ReplyData packet. ******************/ private void handleClassDesc(RMIObject obj, LinkedList<Byte> dataStack) throws BaRMIeInvalidReplyDataPacketException { String className; //Delegate depending on the type of classDesc switch(dataStack.pop()) { //ClassDesc case ObjectStreamConstants.TC_CLASSDESC: //Read the class name className = this.extractUtf8(dataStack); //Skip over the serialVersionUID this.extractLong(dataStack); //Handle the classDescInfo element, pass the class name in as there may be annotations for the class in there this.handleClassDescInfo(obj, dataStack, className); break; //ProxyClassDesc case ObjectStreamConstants.TC_PROXYCLASSDESC: //Handle the proxyClassDescInfo element this.handleProxyClassDescInfo(obj, dataStack); break; //Null - e.g. when the super class is null case ObjectStreamConstants.TC_NULL: break; //Unknown classDesc type default: throw new BaRMIeInvalidReplyDataPacketException("Unknown classDesc element type."); } }
/******************* * Handle a classAnnotation element and return any string annotation * elements in the classAnnotation. * * @param obj The RMIObject to populate with class names. * @param dataStack The remaining data in the ReplyData packet. * @return An ArrayList of strings representing any string annotations extracted from the stream. ******************/ private ArrayList<String> handleClassAnnotation(RMIObject obj, LinkedList<Byte> dataStack) throws BaRMIeInvalidReplyDataPacketException { ArrayList<String> stringAnnotations; byte b; //Create the arraylist stringAnnotations = new ArrayList<String>(); //Read elements from the stream until a TC_ENDBLOCKDATA element is read while((b = dataStack.pop()) != ObjectStreamConstants.TC_ENDBLOCKDATA) { //Handle the annotation switch(b) { //Read string annotations into an array list to return case ObjectStreamConstants.TC_STRING: stringAnnotations.add(this.extractUtf8(dataStack)); break; //Skip over reference annotations case ObjectStreamConstants.TC_REFERENCE: //Read past the reference handle this.extractInt(dataStack); break; //Ignore null annotations... case ObjectStreamConstants.TC_NULL: break; //Unknown annotation type default: throw new BaRMIeInvalidReplyDataPacketException("Unknown classAnnotation element type (0x" + String.format("%02x", b) + ")."); } } //Return the string annotations return stringAnnotations; }
/******************* * Handle an objectAnnotation element, extracting the object endpoint * details if found. * * @param obj The RMIObject to populate with class names. * @param dataStack The remaining data in the ReplyData packet. ******************/ private void handleObjectAnnotation(RMIObject obj, LinkedList<Byte> dataStack) throws BaRMIeInvalidReplyDataPacketException { byte b; //Read elements from the stream until a TC_ENDBLOCKDATA element is read while((b = dataStack.pop()) != ObjectStreamConstants.TC_ENDBLOCKDATA) { //Handle the annotation switch(b) { //Look for object endpoint details in block data elements case ObjectStreamConstants.TC_BLOCKDATA: //Push the block type back on to the stack and extract endpoint details if found dataStack.push(ObjectStreamConstants.TC_BLOCKDATA); this.extractObjectEndpointFromBlockData(obj, dataStack); break; //Skip over object annotations case ObjectStreamConstants.TC_OBJECT: this.handleNewObjectElement(obj, dataStack); break; //Ignore null annotations... case ObjectStreamConstants.TC_NULL: break; //Unknown annotation type default: throw new BaRMIeInvalidReplyDataPacketException("Unknown classAnnotation element type (0x" + String.format("%02x", b) + ")."); } } }
/** * Creates a new <code>MarshalledObjectOutputStream</code> whose * non-location bytes will be written to <code>objOut</code> and whose * location annotations (if any) will be written to * <code>locOut</code>. */ MarshalledObjectOutputStream(OutputStream objOut, OutputStream locOut) throws IOException { super(objOut); this.useProtocolVersion(ObjectStreamConstants.PROTOCOL_VERSION_2); this.locOut = new ObjectOutputStream(locOut); hadAnnotations = false; }
/** * Verify the class cannot be deserialized from a handcoded stream. * Fail if the deserialization does <em>not</em> throw an Exception. * @param serClass the class to embed in the handcoded stream * @throws Exception if an unexpected condition occurs */ protected static void assertNotSerializable(Class<?> serClass) throws Exception { Field field = serClass.getDeclaredField("serialVersionUID"); field.setAccessible(true); long serVer = (Long) field.get(null); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (DataOutputStream out = new DataOutputStream(baos)) { out.writeShort(ObjectStreamConstants.STREAM_MAGIC); out.writeShort(ObjectStreamConstants.STREAM_VERSION); out.writeByte(ObjectStreamConstants.TC_OBJECT); out.writeByte(ObjectStreamConstants.TC_CLASSDESC); out.writeUTF(serClass.getName()); out.writeLong(serVer); out.writeByte(ObjectStreamConstants.SC_SERIALIZABLE); // Flags ObjectStreamConstants out.writeShort(0); // number of fields out.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); out.writeByte(ObjectStreamConstants.TC_NULL); // no superclasses } byte[] bytes = baos.toByteArray(); try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream in = new ObjectInputStream(bis)) { Object o = in.readObject(); } catch (Exception ioe) { // Expected exception return; } fail("Class should not be deserializable " + serClass.getName()); }
/** * Verify the class cannot be deserialized from a handcoded stream. * Fail if the deserialization does <em>not</em> throw an Exception. * @param serClass the class to embed in the handcoded stream * @throws Exception if an unexpected condition occurs */ protected static void assertNotSerializable(Class<?> serClass) throws Exception { long serVer = getSUID(serClass); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (DataOutputStream out = new DataOutputStream(baos)) { out.writeShort(ObjectStreamConstants.STREAM_MAGIC); out.writeShort(ObjectStreamConstants.STREAM_VERSION); out.writeByte(ObjectStreamConstants.TC_OBJECT); out.writeByte(ObjectStreamConstants.TC_CLASSDESC); out.writeUTF(serClass.getName()); out.writeLong(serVer); out.writeByte(ObjectStreamConstants.SC_SERIALIZABLE); // Flags ObjectStreamConstants out.writeShort(0); // number of fields out.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); out.writeByte(ObjectStreamConstants.TC_NULL); // no superclasses } byte[] bytes = baos.toByteArray(); try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream in = new ObjectInputStream(bis)) { Object o = in.readObject(); } catch (Exception ioe) { // Expected exception return; } fail("Class should not be deserializable " + serClass.getName()); }
@Test() public void test_hijrahSerialization_format() throws Exception { HijrahChronology chrono = HijrahChronology.INSTANCE; HijrahDate date = HijrahDate.of(1433, 10, 29); ByteArrayOutputStream baos = new ByteArrayOutputStream(); // Expect the type of the HijrahDate in the stream byte[] hijrahDateBytes = new byte[] {HIJRAH_DATE_TYPE}; // Literal reference to Hijrah-Umalqura Chronology byte[] hijrahChronoBytes = new byte[] { 115, 113, 0, 126, 0, 0, /* p w \u0001 \u0006 s q \u0000 ~ \u0000 \u0000 */ 119, 18, 1, 0, 15, 72, 105, 106, 114, 97, /* w \u0012 \u0001 \u0000 \u000f H i j r a */ 104, 45, 117, 109, 97, 108, 113, 117, 114, 97, /* h - u m a l q u r a */ 120, /* \u001d x */ }; // Build the sequence that represents the data in the stream baos = new ByteArrayOutputStream(); try (DataOutputStream dos = new DataOutputStream(baos) ) { dos.writeByte(ObjectStreamConstants.TC_BLOCKDATA); dos.writeByte(6); // 6 bytes follow dos.writeInt(date.get(YEAR)); dos.writeByte(date.get(MONTH_OF_YEAR)); dos.writeByte(date.get(DAY_OF_MONTH)); dos.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); } byte[] dateBytes = baos.toByteArray(); assertSerializedBySer(date, hijrahDateBytes, hijrahChronoBytes, dateBytes); }
@Override protected void decodeLast(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception { switch (buffer.readableBytes()) { case 0: return; case 1: // Ignore the last TC_RESET if (buffer.getByte(buffer.readerIndex()) == ObjectStreamConstants.TC_RESET) { buffer.skipBytes(1); return; } } decode(ctx, buffer, out); }
@SuppressWarnings("ThrowableResultOfMethodCallIgnored") @Test void testStashAnyFails() { RuntimeException e; e = assertThrows(RuntimeException.class, () -> stashAny(buffer, new Thread())); assertEquals(NotSerializableException.class, e.getCause().getClass()); // spawn from corrupt stream buffer.clear(); stashByteArray(buffer, new byte[] {1, 4, 5, 6, 7, 8}); buffer.flip(); e = assertThrows(RuntimeException.class, () -> spawnAny(buffer)); assertEquals(StreamCorruptedException.class, e.getCause().getClass()); // spawn from truncated stream buffer.clear(); stashAny(buffer, "abc"); buffer.flip(); buffer.limit(buffer.limit() - 3); e = assertThrows(RuntimeException.class, () -> spawnAny(buffer)); assertEquals(BufferUnderflowException.class, e.getClass()); // spawn from modified stream 1 buffer.clear(); stashAny(buffer, "abc"); buffer.flip(); buffer.put(6, (byte) 2); e = assertThrows(RuntimeException.class, () -> spawnAny(buffer)); assertEquals(EOFException.class, e.getCause().getClass()); // spawn from modified stream 2 buffer.clear(); stashAny(buffer, "abc"); buffer.flip(); buffer.put(5, ObjectStreamConstants.TC_OBJECT); e = assertThrows(RuntimeException.class, () -> spawnAny(buffer)); assertEquals(StreamCorruptedException.class, e.getCause().getClass()); }
@Override protected void writeObject(ObjectOutput out, Object obj, Map<Object, Integer> cache, byte version) throws IOException { String str = (String)obj; if (str.length() <= MAX_UTF) { //skip object serialization if we have a short string out.writeByte(ObjectStreamConstants.TC_STRING); out.writeUTF(str); } else { out.writeByte(ObjectStreamConstants.TC_LONGSTRING); out.writeObject(obj); } }
@Override protected Object readObject(ObjectInput in, List<Object> cache, byte version) throws IOException, ClassNotFoundException { if (in.readByte() == ObjectStreamConstants.TC_STRING) { return in.readUTF(); } return super.readObject(in, cache, version); }
public static void main(String[] args) { byte[] ref = new byte[4]; ref[0] = ObjectStreamConstants.TC_BASE; ref[1] = ObjectStreamConstants.TC_NULL; ref[2] = ObjectStreamConstants.TC_REFERENCE; ref[3] = ObjectStreamConstants.TC_CLASSDESC; int version = ObjectStreamConstants.PROTOCOL_VERSION_1; }
/** * Creates a serial output stream. * * @param out is the output stream to which the compact serialized objects * will be written. * * @param classCatalog is the catalog to which the class descriptions for * the serialized objects will be written. */ public SerialOutput(OutputStream out, ClassCatalog classCatalog) throws IOException { super(out); this.classCatalog = classCatalog; /* guarantee that we'll always use the same serialization format */ useProtocolVersion(ObjectStreamConstants.PROTOCOL_VERSION_2); }