public inbox for mauve-discuss@sourceware.org
 help / color / mirror / Atom feed
* Re: ClassLoader.findLoadedClass (was: ServiceFactory)
@ 2004-03-22 13:15 Robert Lougher
  2004-03-23  0:44 ` David Holmes
  0 siblings, 1 reply; 8+ messages in thread
From: Robert Lougher @ 2004-03-22 13:15 UTC (permalink / raw)
  To: brawer, dholmes, chris, aph; +Cc: classpath, mauve-discuss

Interesting -- that's a documentation change between 1.3 and 1.4.  In the 
specs for 1.3 it simply says:

protected final Class findLoadedClass(String name)
"Finds the class with the given name if it had been previously loaded 
through this class loader."

Which is suitably vague enough for several interpretations.  Pragmatically, 
a class loader must keep track of the classes defined by itself so it 
doesn't try to define them again.  This appears to be 
Classpaths'interpretation.

However, as Sascha points out, 1.4's explicitly says it should return 
classes _recorded by the virtual machine_ as initiated by the loader. 
Strictly, this doesn't mean all classes initiated by the loader, just the 
ones recorded by the VM.  As I said, if loadClass is called implicitly by 
the VM it's recorded as an initiating loader, but not if loadClass is called 
explicitly by the programmer.  The JDK is therefore correct, as loadClass 
was called explicitly.

In fact, nowhere in the documentation does it say that calling loadClass on 
a class loader makes it an initiating loader of the returned class!

The bad news is that Classpath (at least 0.07) is wrong according to the new 
documentation.  It won't handle classes recorded by the VM as being 
initiated by it.  Perhaps it should be moved into the VM class, so that a VM 
can do it natively using its internal class tables?  (Alternatively, a VM 
can implement it as a call back to record it as an initiating loader).

Rob.

----Original Message Follows----
From: Sascha Brawer <brawer@dandelis.ch>
To: David Holmes <dholmes@dltech.com.au>, Chris Gray 
<chris@kiffer.eunet.be>, Andrew Haley <aph@redhat.com>, Robert Lougher 
<robert_lougher@hotmail.com>
CC: GNU Classpath <classpath@gnu.org>, <mauve-discuss@sources.redhat.com>
Subject: Re: ClassLoader.findLoadedClass (was: ServiceFactory)
Date: Mon, 22 Mar 2004 10:15:54 +0100

Robert Lougher <robert_lougher@hotmail.com> wrote on Mon, 22 Mar 2004 09:
03:12 +0000:

 >However, in the explicit case, the initiator has been lost --
 >defineClass only has the defining loader, and we don't have an "add
 >initiating loader" call for use when we unwind.  Even if findLoadedClass 
was
 >native so it could use the VM class cache, the VM wouldn't know that, 
using
 >your example, L1 initiated the load and would return null.

Does this mean that the API specification for ClassLoader.findLoadedClass
is incorrect? Or should it say that a VM may or may not record the fact that
some ClassLoader has initiated the loading of a class?

 > protected final Class findLoadedClass(String name)
 >
 >   Returns the class with the given name if this loader has been recorded
 >   by the Java virtual machine as an initiating loader of a class with
 >   that name. Otherwise null is returned.

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/
ClassLoader.html#findLoadedClass(java.lang.String)

-- Sascha

Sascha Brawer, brawer@dandelis.ch, http://www.dandelis.ch/people/brawer/

_________________________________________________________________
Express yourself with cool new emoticons http://www.msn.co.uk/specials/myemo

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: ClassLoader.findLoadedClass (was: ServiceFactory)
  2004-03-22 13:15 ClassLoader.findLoadedClass (was: ServiceFactory) Robert Lougher
@ 2004-03-23  0:44 ` David Holmes
  2004-03-23 17:25   ` Archie Cobbs
  0 siblings, 1 reply; 8+ messages in thread
From: David Holmes @ 2004-03-23  0:44 UTC (permalink / raw)
  To: Robert Lougher, brawer, chris, aph; +Cc: classpath, mauve-discuss

Robert Lougher wrote:
> Interesting -- that's a documentation change between 1.3 and 1.4.

Yes see:

http://developer.java.sun.com/developer/bugParade/bugs/4474902.html

and then:

http://developer.java.sun.com/developer/bugParade/bugs/4778645.html

The change to "initiating classloader" was very deliberately done.

> However, as Sascha points out, 1.4's explicitly says it should return
> classes _recorded by the virtual machine_ as initiated by the loader.
> Strictly, this doesn't mean all classes initiated by the loader, just the
> ones recorded by the VM.  As I said, if loadClass is called implicitly by
> the VM it's recorded as an initiating loader, but not if
> loadClass is called explicitly by the programmer.

Allow me to take a walk through the spec here :)

Section 5.3.2 of the JVMS states that after invoking loadClass on a loader
the JVM records that the loader is an initiating loader of that class. This
implies that the loaded class cache is maintained by the VM not the loader.
However, if you read the OOPSLA '98 paper by Sheng Liang and Gilda Bracha
"Dynamic Class Loading in the Java Virtual Machine, (which is referred to by
the JLS and JVMS) it states that ClassLoader.findLoadedClass is the method
that performs that lookup in the loaded class cache.

So this supports Robert's position that only classes loaded by the VM get
registered in the loaded class cache in this way. However, we now need to
look at what happens if loadClass is called programmatically. For loadClass
to actually return a Class object it must either successfully use
defineClass - which is a final method and therefore part of the VM - or it
must successfully delegate to a parent loader.

According to JVMS 5.3.5 the final step in a successful defineClass is that
the JVM marks the class as having that loader as its defining loader AND
having that loader as an initiating loader. Hence after a successful
l.defineClass(n) we must have l.findLoadedClass(n) returning true.

If delegation is used then 5.3 defines that the loader is an initiating
loader of the class.

However, there is no explicit rule in 5.3 that states when in the delegation
process the "initiating" loader is marked as an initiating loader. Similarly
there is no obvious rule that states that when A delegates to B which
delegates to C etc that any of the intervening loaders are marked as
initiating loaders, even though by definition they are.

So I conclude that Robert is correct. Although in Sascha's example, the
classloader in question was by definition an initiating loader, it had not
been used in a way that required it to be marked by the VM as an initiating
loader and hence findLoadedClass was not required to return true.

Initially I thought this exposed a hole in the type system but then realized
that it does not. For although a given class could hold two reference to
objects of Class N where N was defined by two different classloaders (L1 and
L2), those references could only be typed as Object. If the class tried to
define a field of type N then it would force marking of the initiating
loader in a way that prevents two different classes for N being returned.

Fun exercise :)

Cheers,
David Holmes

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: ClassLoader.findLoadedClass (was: ServiceFactory)
  2004-03-23  0:44 ` David Holmes
@ 2004-03-23 17:25   ` Archie Cobbs
  2004-03-23 23:59     ` David Holmes
  0 siblings, 1 reply; 8+ messages in thread
From: Archie Cobbs @ 2004-03-23 17:25 UTC (permalink / raw)
  To: David Holmes; +Cc: Robert Lougher, brawer, chris, aph, classpath, mauve-discuss

David Holmes wrote:
> Allow me to take a walk through the spec here :)

This is all very interesting and making my brain hurt :-) I'm trying to
figure out now if the JC vm does the right thing. Hopefully this email
will not add to the confusion.

JC will record C in the (internal to the VM) initiated types table
associated with a class loader L if and only if:

(a) L is the defining loader for C (i.e., L.defineClass(C) was called); or

(b) L.loadClass(C) successfully returns after being called **from
    within the VM itself** (e.g., as a result of the VM's trying
    to resolve a symbolic reference).

So if another loader L2 delegates the loading of C to L, then L is not
marked as an initiating loader for C, as neither (a) nor (b) happens.

Is this consistent and/or correct with the current understanding?

Also: this discussion seems to imply that we require a native method
that findLoadedClass() can use to ask the VM to look for C in its internal
initiated types table associated with L.. is that correct?

At one time I remember concluding that to satisfy the specs, even though
the ClassLoader object may have a Hashtable of loaded classes or whatever,
the VM must have its own internal initiated types table associated with each
class loader. If this is true, then findLoadedClass() simply needs to look
into it - requiring a native method. I believe this is because the VM can't
rely on the ClassLoader implementation to do the right thing with respect
to not trying to load the same class twice.

Classpath has this:

    protected final synchronized Class findLoadedClass(String name)
    {
	// NOTE: If the VM is keeping its own cache, it may make sense to have
	// this method be native.
	return (Class) loadedClasses.get(name);
    }

Perhaps then the comment should be removed and this method made native
always?

Thanks,
-Archie

__________________________________________________________________________
Archie Cobbs      *        CTO, Awarix        *      http://www.awarix.com

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: ClassLoader.findLoadedClass (was: ServiceFactory)
  2004-03-23 17:25   ` Archie Cobbs
@ 2004-03-23 23:59     ` David Holmes
  0 siblings, 0 replies; 8+ messages in thread
From: David Holmes @ 2004-03-23 23:59 UTC (permalink / raw)
  To: Archie Cobbs; +Cc: Robert Lougher, brawer, chris, aph, classpath, mauve-discuss

Archie Cobbs wrote:
> JC will record C in the (internal to the VM) initiated types table
> associated with a class loader L if and only if:
>
> (a) L is the defining loader for C (i.e., L.defineClass(C) was called); or
>
> (b) L.loadClass(C) successfully returns after being called **from
>     within the VM itself** (e.g., as a result of the VM's trying
>     to resolve a symbolic reference).
>
> So if another loader L2 delegates the loading of C to L, then L is not
> marked as an initiating loader for C, as neither (a) nor (b) happens.
>
> Is this consistent and/or correct with the current understanding?

Sounds consistent and correct to me.

> Also: this discussion seems to imply that we require a native method
> that findLoadedClass() can use to ask the VM to look for C in its internal
> initiated types table associated with L.. is that correct?

As findLoadedClass is a final method in ClassLoader I consider its
implementation part of the VM - as long as it and other parts of the VM use
the same lookup table you can do whatever you like here. That said it seems
to me that the lookup table defined in ClassLoader should be moved to
VMClassLoader. That way we would have:

  ClassLoader.findLoadedClass(n) calls VMClassLoader.findLoadedClass(this,
n)

and

  ClassLoader.defineClass calls VMClassLoader.defineClass(this, ...) and
VMClassLoader.defineClass can then update the lookup table however it is
implemented in that VM.

VMClassLoader can define a default mechanism using hashtables or just leave
things native.

Or in simple words: move the lookup table out of ClassLoader into
VMClassLoader.


David Holmes

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: ClassLoader.findLoadedClass (was: ServiceFactory)
  2004-03-24 10:40 Robert Lougher
@ 2004-03-25  0:02 ` David Holmes
  0 siblings, 0 replies; 8+ messages in thread
From: David Holmes @ 2004-03-25  0:02 UTC (permalink / raw)
  To: Robert Lougher; +Cc: classpath, mauve-discuss

Robert Lougher wrote:
> Yes, I agree (but see my comment below). >
> ...
> A pure Java "reference" implementation won't work.  At the Java level
> VMClassLoader can only keep track of classes defined by a loader (when it
> calls VMClassLoader.defineClass). A call back will be needed so
> that the VM can record a loader as an initiating loader for a class.

Well you don't need an explicit callback as that's likely to be VM specific.
The VM can directly access the Java-level hashtable(s) if it needs to using
JNI or whatever means that particular VM has. The only thing you need in the
reference implementation is a comment saying that the VM must keep the
tables up to date.

That said, I don't see much value in a "reference implementation" for this
particular feature.

David Holmes

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: ClassLoader.findLoadedClass (was: ServiceFactory)
@ 2004-03-24 10:40 Robert Lougher
  2004-03-25  0:02 ` David Holmes
  0 siblings, 1 reply; 8+ messages in thread
From: Robert Lougher @ 2004-03-24 10:40 UTC (permalink / raw)
  To: dholmes, archie; +Cc: brawer, chris, aph, classpath, mauve-discuss

Yes, I agree (but see my comment below).  Iin fact, I suggested moving 
findLoadedClass to the VMClassLoader in my last post.  The next release of 
JamVM, which should be out tonight, will have this.  This means releasing a 
modified ClassLoader as a "VM class" but it'll be a while before this makes 
it into the next release of Classpath.

Thanks,

Rob.

----Original Message Follows----
From: "David Holmes" <dholmes@dltech.com.au>

...

>VMClassLoader can define a default mechanism using hashtables or just leave
>things native.
>

A pure Java "reference" implementation won't work.  At the Java level 
VMClassLoader can only keep track of classes defined by a loader (when it 
calls VMClassLoader.defineClass). A call back will be needed so that the VM 
can record a loader as an initiating loader for a class.

>Or in simple words: move the lookup table out of ClassLoader into
>VMClassLoader.


David Holmes

_________________________________________________________________
Use MSN Messenger to send music and pics to your friends 
http://www.msn.co.uk/messenger

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: ClassLoader.findLoadedClass (was: ServiceFactory)
  2004-03-22  8:14 ` Sascha Brawer
@ 2004-03-22  9:16   ` Sascha Brawer
  0 siblings, 0 replies; 8+ messages in thread
From: Sascha Brawer @ 2004-03-22  9:16 UTC (permalink / raw)
  To: David Holmes, Chris Gray, Andrew Haley, Robert Lougher
  Cc: GNU Classpath, mauve-discuss

Robert Lougher <robert_lougher@hotmail.com> wrote on Mon, 22 Mar 2004 09:
03:12 +0000:

>However, in the explicit case, the initiator has been lost --
>defineClass only has the defining loader, and we don't have an "add
>initiating loader" call for use when we unwind.  Even if findLoadedClass was
>native so it could use the VM class cache, the VM wouldn't know that, using
>your example, L1 initiated the load and would return null.

Does this mean that the API specification for ClassLoader.findLoadedClass
is incorrect? Or should it say that a VM may or may not record the fact that
some ClassLoader has initiated the loading of a class?

> protected final Class findLoadedClass(String name)
>
>   Returns the class with the given name if this loader has been recorded
>   by the Java virtual machine as an initiating loader of a class with
>   that name. Otherwise null is returned.

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/
ClassLoader.html#findLoadedClass(java.lang.String)

-- Sascha

Sascha Brawer, brawer@dandelis.ch, http://www.dandelis.ch/people/brawer/


^ permalink raw reply	[flat|nested] 8+ messages in thread

* ClassLoader.findLoadedClass (was: ServiceFactory)
       [not found] <NFBBKALFDCPFIDBNKAPCIEFEDPAA.dholmes@dltech.com.au>
@ 2004-03-22  8:14 ` Sascha Brawer
  2004-03-22  9:16   ` Sascha Brawer
  0 siblings, 1 reply; 8+ messages in thread
From: Sascha Brawer @ 2004-03-22  8:14 UTC (permalink / raw)
  To: David Holmes, Chris Gray, Andrew Haley; +Cc: GNU Classpath, mauve-discuss

[-- Attachment #1: Type: text/plain, Size: 1341 bytes --]

David Holmes <dholmes@dltech.com.au> wrote on Mon, 22 Mar 2004 09:22:43 +1000:

From what I've read, the specification of findLoadedClass and definition of
>the class cache in terms of an initiating classloader, are intended to
>prevent a malicious classloader from breaking the lookup process. If each
>classloader delegates correctly to its parent then there is, as you say, no
>harm. However, if the parent does not play nicely then different class
>instances could be returned.
>
>This seems like a bug in the JDK implementation of findLoadedClass.

Please find attached a testcase for Mauve (put the two files into gnu/
testlet/java/lang/ClassLoader).

My understanding of the API spec [1] is that on line 51 of the testlet,
the result of calling findLoadedClass should be 'klass' because 'loader'
is an initiating loader for "gnu.testlet.java.lang.ClassLoader.TestClass". 

[1] http://java.sun.com/j2se/1.5.0/docs/api/java/lang/
ClassLoader.html#findLoadedClass(java.lang.String)

On JDK 1.4.1_01, the testlet fails because the result returns null. Same
for JamVM, which is based on Classpath.

If people agree that both the JDK and the Classpath-based VMs are buggy,
I'd commit the test case into Mauve and file bug reports with Classpath
and Sun.

-- Sascha

Sascha Brawer, brawer@dandelis.ch, http://www.dandelis.ch/people/brawer/ 

[-- Attachment #2.1: TestClass.java --]
[-- Type: text/plain, Size: 947 bytes --]

// Tags: not-a-test

// Copyright (C) 2004 Sascha Brawer <brawer@dandelis.ch>

// This file is part of Mauve.

// Mauve is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.

// Mauve is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Mauve; see the file COPYING.  If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.

package gnu.testlet.java.lang.ClassLoader;

/**
 * Used by gnu.testlet.java.lang.ClassLoader.findLoadedClass.
 */
public class TestClass
{
}

[-- Attachment #2.2: findLoadedClass.java --]
[-- Type: text/plain, Size: 2023 bytes --]

// Tags: JDK1.2
// Uses: TestClass

// Copyright (C) 2004 Sascha Brawer <brawer@dandelis.ch>

// This file is part of Mauve.

// Mauve is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.

// Mauve is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Mauve; see the file COPYING.  If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.

package gnu.testlet.java.lang.ClassLoader;

import gnu.testlet.Testlet;
import gnu.testlet.TestHarness;


/**
 * @author <a href="mailto:brawer@dandelis.ch">Sascha Brawer</a>
 */
public class findLoadedClass
  implements Testlet
{
  public void test(TestHarness h)
  {
    CustomClassLoader loader;
    String name;
    Class klass;

    // Check #1: Ask a ClassLoader to load a class, then check
    // whether its findLoadedClass method returns it.
    //
    // Fails with JDK 1.4.1_01 (for GNU/Linux on IA-32) because
    // its ClassLoader.findLoadedClass returns null here.
    loader = new CustomClassLoader();
    name = "gnu.testlet.java.lang.ClassLoader.TestClass";
    try
      {
        klass = loader.loadClass(name);
        h.check(loader.callFindLoadedClass(name), klass);
      }
    catch (ClassNotFoundException cnfex)
      {
        h.check(false);
        h.debug(cnfex);
      }
  }

  
  private static class CustomClassLoader
    extends ClassLoader
  {
    /**
     * Returns the result of calling the protected method {@link
     * ClassLoader#findLoadedClass}.
     */
    public Class callFindLoadedClass(String name)
    {
      return findLoadedClass(name);
    }
  }
}

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2004-03-25  0:02 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-03-22 13:15 ClassLoader.findLoadedClass (was: ServiceFactory) Robert Lougher
2004-03-23  0:44 ` David Holmes
2004-03-23 17:25   ` Archie Cobbs
2004-03-23 23:59     ` David Holmes
  -- strict thread matches above, loose matches on Subject: below --
2004-03-24 10:40 Robert Lougher
2004-03-25  0:02 ` David Holmes
     [not found] <NFBBKALFDCPFIDBNKAPCIEFEDPAA.dholmes@dltech.com.au>
2004-03-22  8:14 ` Sascha Brawer
2004-03-22  9:16   ` Sascha Brawer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).