classpath
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Loader in ObjectStreamClass.readClassDescriptor


From: Nicolas Geoffray
Subject: Re: Loader in ObjectStreamClass.readClassDescriptor
Date: Tue, 02 Aug 2005 14:08:07 +0200
User-agent: Mozilla Thunderbird 1.0.6 (X11/20050725)

Hi everyone,

sorry for the typo, it was ObjectInputStream.readClassDescriptor that misbehaves.

Shortly, when a reading a given class descriptor CL, it loads the class of a field from CL with the currentClassLoader on the stack. But in RMI, the currentClassLoader is null, so loading the fields' classes won't work for classes that are not in the bootclasspath (glibj.zip). The algorithm with RMI will however succeed to load the class CL itself because it uses the method resolveClass from gnu.java.rmi.server.RMIObjectInputStream. The patch given fixes the problem by loading the fields' class of CL with CL's classloader.

While we're at it, there might also be something to change in, this time, ObjectStreamClass.setClass. In the method it tries to compare the serial uids bewteen the local class and the stream class. It does it for all classes, even for array classes, which is wrong because array classes do not have serial uids.

I'm also interested to know how compatible are the algorithms between java and gnu classpath for computing the serial version uid? When I tried to communicate a sun vm with mine, it says that my HelloWorld class isn't compatible between the vms. Is that
normal or are the algorithms compatibles and I did something wrong?

Thanks all for your attention
Cheers,
Nicolas

Nicolas Geoffray wrote:

Hello again,

There's something that, I think, misbehaves in readClassDescriptor.

Fields are read before the loading of the actual object's class CL in the stream, which is necessary. When loading the classes of the fields (before loading CL), the classloader given is the callersClassLoader which is set to currentLoader() the most recent user defined classloader on the execution stack.

When using the method with RMI here is the class context :
class java.io.VMObjectInputStream$1
class java.security.AccessController
class java.io.VMObjectInputStream
class java.io.ObjectInputStream
class java.io.ObjectInputStream
class java.io.ObjectInputStream
class java.io.ObjectInputStream
class gnu.java.rmi.server.RMIObjectInputStream
class gnu.java.rmi.server.UnicastServerRef
class gnu.java.rmi.server.UnicastServer
class gnu.java.rmi.server.UnicastServer
class gnu.java.rmi.server.UnicastConnection
class java.lang.Thread
class java.lang.VMThread

So the callersClassLoader is set to null and the fields of CL are loaded with the VM ClassLoader (which won't found any classes loaded by the application class loader or other user defined classloader)

Because RMI redefines the resolveClass(ObjectStreamClass), CL is found, as it used the "correct" classloader. The problem arrives when CL was loaded by MyClassLoader, and CL has one field whose class was also loaded by MyClassLoader.

What I suggest is to use the classloader of CL, once CL is loaded, to load the fields. What i do in the attached patch is reading the fields and storing them in a temporary class, loading CL as it was done before (this is when the RMI's resolveClass is used : gnu.java.rmi.server.RMIObjectInputStream) and finally loading the fields with CL's classloader.

Would that be a correct behaviour?

Cheers
Nicolas

------------------------------------------------------------------------

*** java/io/ObjectInputStream.java      Fri Jul 15 15:57:35 2005
--- java/io/ObjectInputStream.java      Fri Jul 22 15:36:01 2005
***************
*** 468,473 ****
--- 468,484 ----
       }
   }
+ + private class TemporaryStreamField{
+     String field_name;
+     String class_name;
+ + TemporaryStreamField(String field, String clazz){
+       field_name = field;
+       class_name = clazz;
+     }
+   }
+ /**
    * This method reads a class descriptor from the real input stream
    * and use these data to create a new instance of ObjectStreamClass.
***************
*** 497,509 ****
     short field_count = this.realInputStream.readShort();
     if(dump) dumpElementln(Short.toString(field_count));
     ObjectStreamField[] fields = new ObjectStreamField[field_count];
     ObjectStreamClass osc = new ObjectStreamClass(name, uid,
                                                  flags, fields);
     assignNewHandle(osc);
- if (callersClassLoader == null)
-       callersClassLoader = currentLoader();
- for (int i = 0; i < field_count; i++)
       {
        if(dump) dumpElement("  TYPE CODE=");
--- 508,518 ----
     short field_count = this.realInputStream.readShort();
     if(dump) dumpElementln(Short.toString(field_count));
     ObjectStreamField[] fields = new ObjectStreamField[field_count];
+     TemporaryStreamField[] temp_fields = new 
TemporaryStreamField[field_count];
     ObjectStreamClass osc = new ObjectStreamClass(name, uid,
                                                  flags, fields);
     assignNewHandle(osc);
for (int i = 0; i < field_count; i++)
       {
        if(dump) dumpElement("  TYPE CODE=");
***************
*** 521,529 ****
          class_name = (String)readObject();
        else
          class_name = String.valueOf(type_code);
! ! fields[i] =
!         new ObjectStreamField(field_name, class_name, callersClassLoader);
       }
/* Now that fields have been read we may resolve the class
--- 530,537 ----
          class_name = (String)readObject();
        else
          class_name = String.valueOf(type_code);
!       
!       temp_fields[i] = new TemporaryStreamField(field_name, class_name);
       }
/* Now that fields have been read we may resolve the class
***************
*** 558,563 ****
--- 566,577 ----
          throw cnfe;
       }
+ ClassLoader loader = clazz.getClassLoader();
+     for(int i =0; i < field_count; i++)
+       fields[i] = new ObjectStreamField(temp_fields[i].field_name,
+             temp_fields[i].class_name, loader);
+ + boolean oldmode = setBlockDataMode(true);
     osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
     classLookupTable.put(clazz, osc);
------------------------------------------------------------------------

_______________________________________________
Classpath mailing list
address@hidden
http://lists.gnu.org/mailman/listinfo/classpath





reply via email to

[Prev in Thread] Current Thread [Next in Thread]