classpath-patches
[Top][All Lists]
Advanced

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

[cp-patches] Native library class loader fixes


From: Archie Cobbs
Subject: [cp-patches] Native library class loader fixes
Date: Sat, 01 Jan 2005 10:44:15 -0600
User-agent: Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041129

And now, for my next controversy... :-)

This patch is to address the issues raised in this bug:

  http://savannah.gnu.org/bugs/?func=detailitem&item_id=7084

and in some prior discussions on this list. These are the basic issues:

1. Native libraries are supposed to be loaded in the context of
   a specific class loader. Therefore, VMRuntime.nativeLoad() needs
   a ClassLoader parameter; currently, it doesn't have one.

2. Our current method of determining the "calling class" or it associated
   class loader has problems. Typically we do this:

   ClassLoader cl = VMSecurityManager.getClassContext()[1].getClassLoader();

   Not only is this inefficient (we throw away all but one element of the
   array) but it's also broken, because if the method was invoked by the
   JNI invocation interface, the Java stack may have length < 2 and so an
   ArrayIndexOutOfBounds exception will be thrown.

3. I've also try to document the semantics of
   VMSecurityManager.getClassContext() more precisely.

Please review and comment. I promise not to commit until everyone
is happy (or at least silent) this time :-)

Thanks,
-Archie

        * NEWS: Document VMRuntime.java and VMSecurityManager.java changes.
        * java/lang/Class.java (newInstance(), getClassLoader(),
        forName(String), forName(String, boolean, ClassLoader)):
        Use new method VMSecurityManager.getCallingClassLoader().
        * java/lang/ClassLoader.java (getParent(), getSystemClassLoader()):
        Likewise.
        * java/lang/Package.java (getPackages()): Likewise.
        * java/lang/Runtime.java (load(), loadLibrary()): Load the native
        library using the calling class' class loader.
        * java/lang/System.java (load(), loadLibrary()): Likewise.
        * vm/reference/java/lang/VMRuntime.java (nativeLoad()):
        Add a ClassLoader parameter.
        * vm/reference/java/lang/VMSecurityManager.java (getCallingClass(),
        getCallingClassLoader()): New methods.
        (getClassContext()): Document requirements more precisely.

__________________________________________________________________________
Archie Cobbs      *        CTO, Awarix        *      http://www.awarix.com
Index: ChangeLog
===================================================================
RCS file: /cvsroot/classpath/classpath/ChangeLog,v
retrieving revision 1.3005
diff -u -r1.3005 ChangeLog
--- ChangeLog   1 Jan 2005 16:14:26 -0000       1.3005
+++ ChangeLog   1 Jan 2005 16:37:26 -0000
@@ -1,3 +1,21 @@
+2005-01-01  Archie Cobbs  <address@hidden>
+
+       * NEWS: Document VMRuntime.java and VMSecurityManager.java changes.
+       * java/lang/Class.java (newInstance(), getClassLoader(),
+       forName(String), forName(String, boolean, ClassLoader)):
+       Use new method VMSecurityManager.getCallingClassLoader().
+       * java/lang/ClassLoader.java (getParent(), getSystemClassLoader()):
+       Likewise.
+       * java/lang/Package.java (getPackages()): Likewise.
+       * java/lang/Runtime.java (load(), loadLibrary()): Load the native
+       library using the calling class' class loader.
+       * java/lang/System.java (load(), loadLibrary()): Likewise.
+       * vm/reference/java/lang/VMRuntime.java (nativeLoad()):
+       Add a ClassLoader parameter.
+       * vm/reference/java/lang/VMSecurityManager.java (getCallingClass(),
+       getCallingClassLoader()): New methods.
+       (getClassContext()): Document requirements more precisely.
+
 2005-01-01  Michael Koch  <address@hidden>
 
        * javax/swing/DefaultBoundedRangeModel.java
Index: NEWS
===================================================================
RCS file: /cvsroot/classpath/classpath/NEWS,v
retrieving revision 1.62
diff -u -r1.62 NEWS
--- NEWS        31 Dec 2004 21:32:17 -0000      1.62
+++ NEWS        1 Jan 2005 16:37:26 -0000
@@ -19,6 +19,10 @@
   implementation, but it is a generic implementation that ignores the
   nano-seconds argument. Runtime hackers are encouraged to provide a more
   efficient version.
+* VMRuntime.nativeLoad() now takes an additional ClassLoader parameter.
+* VMSecurityManager has two new methods with non-native implementations,
+  getCallingClass() and getCallingClassLoader(). VM implementors are
+  encouraged to provide more efficient versions.
 
 New in release 0.12 (Nov 14, 2004)
 
Index: java/lang/Class.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/lang/Class.java,v
retrieving revision 1.28
diff -u -r1.28 Class.java
--- java/lang/Class.java        27 Dec 2004 11:39:28 -0000      1.28
+++ java/lang/Class.java        1 Jan 2005 16:37:28 -0000
@@ -157,7 +157,7 @@
     Class result = VMClass.forName (name);
     if (result == null)
       result = Class.forName(name, true,
-                            
VMSecurityManager.getClassContext()[1].getClassLoader());
+       VMSecurityManager.getCallingClassLoader());
     return result;
   }
 
@@ -198,9 +198,8 @@
         SecurityManager sm = SecurityManager.current;
         if (sm != null)
           {
-            // Get the calling class and classloader
-            Class c = VMSecurityManager.getClassContext()[1];
-            ClassLoader cl = c.getClassLoader();
+            // Get the calling classloader
+            ClassLoader cl = VMSecurityManager.getCallingClassLoader();
             if (cl != null)
               sm.checkPermission(new RuntimePermission("getClassLoader"));
           }
@@ -278,9 +277,8 @@
     SecurityManager sm = SecurityManager.current;
     if (sm != null)
       {
-        // Get the calling class and classloader
-        Class c = VMSecurityManager.getClassContext()[1];
-        ClassLoader cl = VMClass.getClassLoader(c);
+        // Get the calling classloader
+       ClassLoader cl = VMSecurityManager.getCallingClassLoader();
         if (cl != null && !cl.isAncestorOf(loader))
           sm.checkPermission(new RuntimePermission("getClassLoader"));
       }
@@ -1132,8 +1130,9 @@
     int modifiers = constructor.getModifiers();
     if (!Modifier.isPublic(modifiers))
       {
-       Class caller = VMSecurityManager.getClassContext()[1];
-       if (caller != this &&
+       Class caller = VMSecurityManager.getCallingClass();
+       if (caller != null &&
+           caller != this &&
            (Modifier.isPrivate(modifiers)
             || getClassLoader() != caller.getClassLoader()
             || !getPackagePortion(getName())
Index: java/lang/ClassLoader.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/lang/ClassLoader.java,v
retrieving revision 1.40
diff -u -r1.40 ClassLoader.java
--- java/lang/ClassLoader.java  6 Dec 2004 20:43:13 -0000       1.40
+++ java/lang/ClassLoader.java  1 Jan 2005 16:37:29 -0000
@@ -520,8 +520,7 @@
     SecurityManager sm = SecurityManager.current;
     if (sm != null)
       {
-        Class c = VMSecurityManager.getClassContext()[1];
-        ClassLoader cl = c.getClassLoader();
+       ClassLoader cl = VMSecurityManager.getCallingClassLoader();
        if (cl != null && ! cl.isAncestorOf(this))
           sm.checkPermission(new RuntimePermission("getClassLoader"));
       }
@@ -763,8 +762,7 @@
     SecurityManager sm = SecurityManager.current;
     if (sm != null)
       {
-       Class c = VMSecurityManager.getClassContext()[1];
-       ClassLoader cl = c.getClassLoader();
+       ClassLoader cl = VMSecurityManager.getCallingClassLoader();
        if (cl != null && cl != StaticData.systemClassLoader)
          sm.checkPermission(new RuntimePermission("getClassLoader"));
       }
Index: java/lang/Package.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/lang/Package.java,v
retrieving revision 1.12
diff -u -r1.12 Package.java
--- java/lang/Package.java      13 Oct 2004 08:24:05 -0000      1.12
+++ java/lang/Package.java      1 Jan 2005 16:37:29 -0000
@@ -286,8 +286,7 @@
   public static Package[] getPackages()
   {
     // Get the caller's classloader
-    Class c = VMSecurityManager.getClassContext()[1];
-    ClassLoader cl = c.getClassLoader();
+    ClassLoader cl = VMSecurityManager.getCallingClassLoader();
     // Sun's implementation returns the packages loaded by the bootstrap
     // classloader if cl is null, but right now our bootstrap classloader
     // does not create any Packages.
Index: java/lang/Runtime.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/lang/Runtime.java,v
retrieving revision 1.15
diff -u -r1.15 Runtime.java
--- java/lang/Runtime.java      29 Dec 2004 11:15:02 -0000      1.15
+++ java/lang/Runtime.java      1 Jan 2005 16:37:30 -0000
@@ -628,16 +628,33 @@
    * before the final ".so" if the VM was invoked by the name "java_g". There
    * may be a security check, of <code>checkLink</code>.
    *
+   * <p>
+   * The library is loaded using the class loader associated with the
+   * class associated with the invoking method.
+   *
    * @param filename the file to load
    * @throws SecurityException if permission is denied
    * @throws UnsatisfiedLinkError if the library is not found
    */
   public void load(String filename)
   {
+    load(filename, VMSecurityManager.getCallingClassLoader());
+  }
+
+  /**
+   * Same as <code>load(String)</code> but using the given loader.
+   *
+   * @param filename the file to load
+   * @param loader class loader, or <code>null</code> for the boot loader
+   * @throws SecurityException if permission is denied
+   * @throws UnsatisfiedLinkError if the library is not found
+   */
+  void load(String filename, ClassLoader loader)
+  {
     SecurityManager sm = SecurityManager.current; // Be thread-safe!
     if (sm != null)
       sm.checkLink(filename);
-    if (loadLib(filename) == 0)
+    if (loadLib(filename, loader) == 0)
       throw new UnsatisfiedLinkError("Could not load library " + filename);
   }
 
@@ -645,15 +662,16 @@
    * Do a security check on the filename and then load the native library.
    *
    * @param filename the file to load
+   * @param loader class loader, or <code>null</code> for the boot loader
    * @return 0 on failure, nonzero on success
    * @throws SecurityException if file read permission is denied
    */
-  private static int loadLib(String filename)
+  private static int loadLib(String filename, ClassLoader loader)
   {
     SecurityManager sm = SecurityManager.current; // Be thread-safe!
     if (sm != null)
       sm.checkRead(filename);
-    return VMRuntime.nativeLoad(filename);
+    return VMRuntime.nativeLoad(filename, loader);
   }
 
   /**
@@ -668,6 +686,10 @@
    * <code>System.mapLibraryName(libname)</code>. There may be a security
    * check, of <code>checkLink</code>.
    *
+   * <p>
+   * The library is loaded using the class loader associated with the
+   * class associated with the invoking method.
+   *
    * @param libname the library to load
    *
    * @throws SecurityException if permission is denied
@@ -678,29 +700,36 @@
    */
   public void loadLibrary(String libname)
   {
+    loadLibrary(libname, VMSecurityManager.getCallingClassLoader());
+  }
+
+  /**
+   * Same as <code>loadLibrary(String)</code> but using the given loader.
+   *
+   * @param libname the library to load
+   * @param loader class loader, or <code>null</code> for the boot loader
+   * @throws SecurityException if permission is denied
+   * @throws UnsatisfiedLinkError if the library is not found
+   */
+  void loadLibrary(String libname, ClassLoader loader)
+  {
     SecurityManager sm = SecurityManager.current; // Be thread-safe!
     if (sm != null)
       sm.checkLink(libname);
-
     String filename;
-    ClassLoader cl = VMSecurityManager.currentClassLoader();
-    if (cl != null)
+    if (loader != null)
       {
-        filename = cl.findLibrary(libname);
-        if (filename != null)
-          {
-            if (loadLib(filename) != 0)
-             return;
-           else
-             throw new UnsatisfiedLinkError("Could not load library " + 
filename);
-          }
+        filename = loader.findLibrary(libname);
+        if (filename != null && loadLib(filename, loader) != 0)
+         return;
+      }
+    else
+      {
+       filename = VMRuntime.mapLibraryName(libname);
+       for (int i = 0; i < libpath.length; i++)
+         if (loadLib(libpath[i] + filename, null) != 0)
+           return;
       }
-
-    filename = VMRuntime.mapLibraryName(libname);
-    for (int i = 0; i < libpath.length; i++)
-      if (loadLib(libpath[i] + filename) != 0)
-       return;
-
     throw new UnsatisfiedLinkError("Could not find library " + libname + ".");
   }
 
Index: java/lang/System.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/lang/System.java,v
retrieving revision 1.46
diff -u -r1.46 System.java
--- java/lang/System.java       29 Dec 2004 11:15:02 -0000      1.46
+++ java/lang/System.java       1 Jan 2005 16:37:30 -0000
@@ -480,6 +480,10 @@
    * check may be performed, <code>checkLink</code>. This just calls
    * <code>Runtime.getRuntime().load(filename)</code>.
    *
+   * <p>
+   * The library is loaded using the class loader associated with the
+   * class associated with the invoking method.
+   *
    * @param filename the code file to load
    * @throws SecurityException if permission is denied
    * @throws UnsatisfiedLinkError if the file cannot be loaded
@@ -487,7 +491,8 @@
    */
   public static void load(String filename)
   {
-    Runtime.getRuntime().load(filename);
+    Runtime.getRuntime().load(filename,
+      VMSecurityManager.getCallingClassLoader());
   }
 
   /**
@@ -495,6 +500,10 @@
    * check may be performed, <code>checkLink</code>. This just calls
    * <code>Runtime.getRuntime().load(filename)</code>.
    *
+   * <p>
+   * The library is loaded using the class loader associated with the
+   * class associated with the invoking method.
+   *
    * @param libname the library file to load
    * @throws SecurityException if permission is denied
    * @throws UnsatisfiedLinkError if the file cannot be loaded
@@ -502,7 +511,8 @@
    */
   public static void loadLibrary(String libname)
   {
-    Runtime.getRuntime().loadLibrary(libname);
+    Runtime.getRuntime().loadLibrary(libname,
+      VMSecurityManager.getCallingClassLoader());
   }
 
   /**
Index: vm/reference/java/lang/VMRuntime.java
===================================================================
RCS file: /cvsroot/classpath/classpath/vm/reference/java/lang/VMRuntime.java,v
retrieving revision 1.7
diff -u -r1.7 VMRuntime.java
--- vm/reference/java/lang/VMRuntime.java       28 Dec 2004 10:28:27 -0000      
1.7
+++ vm/reference/java/lang/VMRuntime.java       1 Jan 2005 16:37:32 -0000
@@ -151,9 +151,10 @@
      * already been mapped to a true filename.
      *
      * @param filename the file to load
+     * @param loader class loader, or <code>null</code> for the boot loader
      * @return 0 on failure, nonzero on success
      */
-    static native int nativeLoad(String filename);
+    static native int nativeLoad(String filename, ClassLoader loader);
 
     /**
      * Map a system-independent "short name" to the full file name.
Index: vm/reference/java/lang/VMSecurityManager.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/vm/reference/java/lang/VMSecurityManager.java,v
retrieving revision 1.10
diff -u -r1.10 VMSecurityManager.java
--- vm/reference/java/lang/VMSecurityManager.java       6 Mar 2002 19:44:44 
-0000       1.10
+++ vm/reference/java/lang/VMSecurityManager.java       1 Jan 2005 16:37:32 
-0000
@@ -48,12 +48,18 @@
 {
   /**
    * Get a list of all the classes currently executing methods on the
-   * Java stack.  getClassContext()[0] is the currently executing method, ie.
-   * the method which called SecurityManager.getClassContext().  (Hint: you
-   * may need to pop off one or more frames: don't include SecurityManager
-   * or VMSecurityManager.getClassContext in your result. Also, be sure that
-   * you correctly handle the context if SecurityManager.getClassContext
-   * was invoked by reflection).
+   * Java stack. <code>getClassContext()[0]</code> is the class associated
+   * with the currently executing method, i.e., the method that called
+   * <code>SecurityManager.getClassContext()</code> or
+   * <code>VMSecurityManager.getClassContext()</code> (possibly through
+   * reflection). So you must be careful to pop off any of these stack
+   * frames from the top of the stack if present:
+   * <ul>
+   * <li><code>SecurityManager.getClassContext()</code>
+   * <li><code>VMSecurityManager.getClassContext()</code>
+   * <li><code>Method.invoke()</code>
+   * <li><code>Constructor.newInstance()</code>
+   * </ul>
    *
    * @return an array of the declaring classes of each stack frame
    */
@@ -70,4 +76,42 @@
    * @return the current ClassLoader
    */
   static native ClassLoader currentClassLoader();
+
+  /**
+   * Get the class associated with the method invoking the method
+   * invoking this method, or <code>null</code> if the stack is not
+   * that deep (e.g., invoked via JNI invocation API). This method
+   * is an optimization for <code>getClassContext()[1]</code>
+   * and should return the same result.
+   *
+   * <p>
+   * VM implementers are encouraged to provide a more efficient
+   * version of this method.
+   */
+  static Class getCallingClass()
+  {
+    Class[] ctx = getClassContext();
+    if (ctx.length < 3)
+      return null;
+    return ctx[2];
+  }
+
+  /**
+   * Get the class loader associated with the Class returned by
+   * <code>getCallingClass()</code>, or <code>null</code> if no
+   * such class exists or it is the boot loader. This method is an
+   * optimization for <code>getClassContext()[1].getClassLoader()</code>
+   * and should return the same result.
+   *
+   * <p>
+   * VM implementers are encouraged to provide a more efficient
+   * version of this method.
+   */
+  static ClassLoader getCallingClassLoader()
+  {
+    Class[] ctx = getClassContext();
+    if (ctx.length < 3)
+      return null;
+    return ctx[2].getClassLoader();
+  }
 }

reply via email to

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