From ffd94572f43f8b2a3697c9718c34ac3275a48262 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Mon, 21 Jul 2003 01:54:06 +0000 Subject: Runtime.java: Comment fix. * java/lang/Runtime.java: Comment fix. * java/lang/ClassLoader.java (isAncestorOf): New method. (getParent): Uncommented security check. Use isAncestorOf. * include/jvm.h (_Jv_CheckAccess): Declare. * java/lang/reflect/natConstructor.cc (newInstance): Perform access check. Include IllegalAccessException.h, ArrayIndexOutOfBoundsException.h. * java/lang/reflect/natArray.cc (newInstance): Pass caller's class loader to _Jv_GetArrayClass. Include ArrayIndexOutOfBoundsException.h. * java/lang/reflect/Field.java: Update comment to reflect status. (equals): Fixed indentation. * java/lang/Class.h (Class): Declare memberAccessCheck, not checkMemberAccess. Make _Jv_CheckAccess a friend. * java/lang/Class.java (memberAccessCheck): New method from Classpath. (checkMemberAccess): Removed. (getDeclaredMethod): Use memberAccessCheck. (getField): Likewise. (getMethod): Likewise. * resolve.cc (_Jv_ResolvePoolEntry): Use _Jv_CheckAccess. (_Jv_SearchMethodInClass): Likewise. * prims.cc (_Jv_CheckAccess): New function. * jni.cc (_Jv_JNI_FindClass): Use getClassLoaderInternal. (_Jv_JNI_GetAnyFieldID): Likewise. * java/lang/natClass.cc (forName): Use getClassLoaderInternal. (getClassLoader): Added security check. (getConstructor): Call memberAccessCheck. (getDeclaredClasses): Likewise. (getDeclaredField): Likewise. (getDeclaredFields): Likewise. (_getConstructors): Likewise. (getDeclaredConstructor): Likewise. (getDeclaredMethods): Likewise. (getFields): Likewise. (getMethods): Likewise. (newInstance): Likewise. (_Jv_MakeVTable): Put method name in exception. * java/lang/reflect/natMethod.cc (getType): Use getClassLoaderInternal. (_Jv_GetTypesFromSignature): Likewise. (invoke): Perform access check. (_Jv_CallAnyMethodA): Removed old FIXME comments. Include ArrayIndexOutOfBoundsException.h. * java/lang/reflect/natField.cc (getType): Use getClassLoaderInternal. (_Jv_CheckFieldAccessibility): Removed. (getAddr): Use _Jv_CheckAccess; find caller. Include ArrayIndexOutOfBoundsException.h. From-SVN: r69621 --- libjava/ChangeLog | 53 ++++++++++++++++++ libjava/include/jvm.h | 5 +- libjava/java/lang/Class.h | 5 +- libjava/java/lang/Class.java | 46 +++++++-------- libjava/java/lang/ClassLoader.java | 20 ++++++- libjava/java/lang/Runtime.java | 4 +- libjava/java/lang/natClass.cc | 87 +++++++++++++++++++---------- libjava/java/lang/reflect/Field.java | 28 +++------- libjava/java/lang/reflect/natArray.cc | 31 ++++++++-- libjava/java/lang/reflect/natConstructor.cc | 22 +++++++- libjava/java/lang/reflect/natField.cc | 42 ++++++++------ libjava/java/lang/reflect/natMethod.cc | 45 +++++++++------ libjava/jni.cc | 4 +- libjava/prims.cc | 20 ++++++- libjava/resolve.cc | 26 ++------- 15 files changed, 286 insertions(+), 152 deletions(-) diff --git a/libjava/ChangeLog b/libjava/ChangeLog index dcf3011..2942cb9 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,9 +1,62 @@ +2003-07-20 Tom Tromey + + * java/lang/Runtime.java: Comment fix. + * java/lang/ClassLoader.java (isAncestorOf): New method. + (getParent): Uncommented security check. Use isAncestorOf. + * include/jvm.h (_Jv_CheckAccess): Declare. + * java/lang/reflect/natConstructor.cc (newInstance): Perform + access check. + Include IllegalAccessException.h, ArrayIndexOutOfBoundsException.h. + * java/lang/reflect/natArray.cc (newInstance): Pass caller's + class loader to _Jv_GetArrayClass. + Include ArrayIndexOutOfBoundsException.h. + * java/lang/reflect/Field.java: Update comment to reflect status. + (equals): Fixed indentation. + * java/lang/Class.h (Class): Declare memberAccessCheck, not + checkMemberAccess. Make _Jv_CheckAccess a friend. + * java/lang/Class.java (memberAccessCheck): New method from + Classpath. + (checkMemberAccess): Removed. + (getDeclaredMethod): Use memberAccessCheck. + (getField): Likewise. + (getMethod): Likewise. + * resolve.cc (_Jv_ResolvePoolEntry): Use _Jv_CheckAccess. + (_Jv_SearchMethodInClass): Likewise. + * prims.cc (_Jv_CheckAccess): New function. + * jni.cc (_Jv_JNI_FindClass): Use getClassLoaderInternal. + (_Jv_JNI_GetAnyFieldID): Likewise. + * java/lang/natClass.cc (forName): Use getClassLoaderInternal. + (getClassLoader): Added security check. + (getConstructor): Call memberAccessCheck. + (getDeclaredClasses): Likewise. + (getDeclaredField): Likewise. + (getDeclaredFields): Likewise. + (_getConstructors): Likewise. + (getDeclaredConstructor): Likewise. + (getDeclaredMethods): Likewise. + (getFields): Likewise. + (getMethods): Likewise. + (newInstance): Likewise. + (_Jv_MakeVTable): Put method name in exception. + * java/lang/reflect/natMethod.cc (getType): Use + getClassLoaderInternal. + (_Jv_GetTypesFromSignature): Likewise. + (invoke): Perform access check. + (_Jv_CallAnyMethodA): Removed old FIXME comments. + Include ArrayIndexOutOfBoundsException.h. + * java/lang/reflect/natField.cc (getType): Use + getClassLoaderInternal. + (_Jv_CheckFieldAccessibility): Removed. + (getAddr): Use _Jv_CheckAccess; find caller. + Include ArrayIndexOutOfBoundsException.h. + 2003-07-20 Michael Koch * java/net/URL.java (URL): Fixed documentation to name an argument correcty, Reformatted one method declaration. (getURLStreamHandler): Added documentation from classpath. + 2003-07-19 Tom Tromey * mauve-libgcj: Don't run CollationElementIterator tests. diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h index 9395feb..38155d3 100644 --- a/libjava/include/jvm.h +++ b/libjava/include/jvm.h @@ -1,6 +1,6 @@ // jvm.h - Header file for private implementation information. -*- c++ -*- -/* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation This file is part of libgcj. @@ -326,6 +326,9 @@ extern void _Jv_GetTypesFromSignature (jmethodID method, JArray **arg_types_out, jclass *return_type_out); +extern jboolean _Jv_CheckAccess (jclass self_klass, jclass other_klass, + jint flags); + extern jobject _Jv_CallAnyMethodA (jobject obj, jclass return_type, jmethodID meth, jboolean is_constructor, JArray *parameter_types, diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index db05cb6..06c9c80 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -243,7 +243,7 @@ public: private: - void checkMemberAccess (jint flags); + void memberAccessCheck (jint flags); void initializeClass (void); @@ -328,6 +328,9 @@ private: friend void _Jv_SetVTableEntries (jclass, _Jv_VTable *, jboolean *); friend void _Jv_MakeVTable (jclass); + friend jboolean _Jv_CheckAccess (jclass self_klass, jclass other_klass, + jint flags); + // Return array class corresponding to element type KLASS, creating it if // necessary. inline friend jclass diff --git a/libjava/java/lang/Class.java b/libjava/java/lang/Class.java index 44f5b5a..bd77691 100644 --- a/libjava/java/lang/Class.java +++ b/libjava/java/lang/Class.java @@ -72,14 +72,7 @@ public final class Class implements Serializable public Method getDeclaredMethod (String methodName, Class[] parameterTypes) throws NoSuchMethodException, SecurityException { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) - { - sm.checkMemberAccess(this, Member.DECLARED); - Package p = getPackage(); - if (p != null) - sm.checkPackageAccess(p.getName()); - } + memberAccessCheck(Member.DECLARED); if ("".equals(methodName) || "".equals(methodName)) throw new NoSuchMethodException(methodName); @@ -101,9 +94,7 @@ public final class Class implements Serializable public Field getField (String fieldName) throws NoSuchFieldException, SecurityException { - SecurityManager s = System.getSecurityManager(); - if (s != null) - s.checkMemberAccess (this, java.lang.reflect.Member.DECLARED); + memberAccessCheck (Member.PUBLIC); Field fld = getField(fieldName, fieldName.hashCode()); if (fld == null) throw new NoSuchFieldException(fieldName); @@ -148,14 +139,7 @@ public final class Class implements Serializable public Method getMethod (String methodName, Class[] parameterTypes) throws NoSuchMethodException, SecurityException { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) - { - sm.checkMemberAccess(this, Member.PUBLIC); - Package p = getPackage(); - if (p != null) - sm.checkPackageAccess(p.getName()); - } + memberAccessCheck(Member.PUBLIC); if ("".equals(methodName) || "".equals(methodName)) throw new NoSuchMethodException(methodName); @@ -334,14 +318,6 @@ public final class Class implements Serializable { } - // Do a security check. - private void checkMemberAccess (int flags) - { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) - sm.checkMemberAccess(this, flags); - } - // Initialize the class. private native void initializeClass (); @@ -361,4 +337,20 @@ public final class Class implements Serializable return ""; return name.substring(0, lastInd); } + + /** + * Perform security checks common to all of the methods that + * get members of this Class. + */ + private void memberAccessCheck(int which) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + { + sm.checkMemberAccess(this, which); + Package pkg = getPackage(); + if (pkg != null) + sm.checkPackageAccess(pkg.getName()); + } + } } diff --git a/libjava/java/lang/ClassLoader.java b/libjava/java/lang/ClassLoader.java index 5ae70cdb..008a19e 100644 --- a/libjava/java/lang/ClassLoader.java +++ b/libjava/java/lang/ClassLoader.java @@ -162,12 +162,10 @@ public abstract class ClassLoader SecurityManager sm = System.getSecurityManager(); if (sm != null) { - /* FIXME: security, getClassContext() not implemented. Class c = VMSecurityManager.getClassContext()[1]; ClassLoader cl = c.getClassLoader(); - if (cl != null && cl != this) + if (cl != null && ! cl.isAncestorOf(this)) sm.checkPermission(new RuntimePermission("getClassLoader")); - */ } return parent; } @@ -996,4 +994,20 @@ public abstract class ClassLoader packageAssertionStatus = new HashMap(); classAssertionStatus = new HashMap(); } + + /** + * Return true if this loader is either the specified class loader + * or an ancestor thereof. + * @param loader the class loader to check + */ + final boolean isAncestorOf(ClassLoader loader) + { + while (loader != null) + { + if (this == loader) + return true; + loader = loader.parent; + } + return false; + } } diff --git a/libjava/java/lang/Runtime.java b/libjava/java/lang/Runtime.java index 932600b..5c6037e 100644 --- a/libjava/java/lang/Runtime.java +++ b/libjava/java/lang/Runtime.java @@ -1,5 +1,5 @@ /* Runtime.java -- access to the VM process - Copyright (C) 1998, 2002 Free Software Foundation + Copyright (C) 1998, 2002, 2003 Free Software Foundation This file is part of GNU Classpath. @@ -65,7 +65,7 @@ public class Runtime /** * The current security manager. This is located here instead of in - * Runtime, to avoid security problems, as well as bootstrap issues. + * System, to avoid security problems, as well as bootstrap issues. * Make sure to access it in a thread-safe manner; it is package visible * to avoid overhead in java.lang. */ diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc index 0db8228..4b08582 100644 --- a/libjava/java/lang/natClass.cc +++ b/libjava/java/lang/natClass.cc @@ -101,7 +101,7 @@ java::lang::Class::forName (jstring className) { klass = t->classAt (i); } - loader = klass->getClassLoader(); + loader = klass->getClassLoaderInternal(); } catch (::java::lang::ArrayIndexOutOfBoundsException *e) { @@ -113,13 +113,31 @@ java::lang::Class::forName (jstring className) java::lang::ClassLoader * java::lang::Class::getClassLoader (void) { -#if 0 - // FIXME: the checks we need to do are more complex. See the spec. - // Currently we can't implement them. java::lang::SecurityManager *s = java::lang::System::getSecurityManager(); if (s != NULL) - s->checkPermission (new RuntimePermission (JvNewStringLatin1 ("getClassLoader"))); -#endif + { + gnu::gcj::runtime::StackTrace *t + = new gnu::gcj::runtime::StackTrace(4); + Class *caller = NULL; + ClassLoader *caller_loader = NULL; + try + { + for (int i = 1; !caller; i++) + { + caller = t->classAt (i); + } + caller_loader = caller->getClassLoaderInternal(); + } + catch (::java::lang::ArrayIndexOutOfBoundsException *e) + { + } + + // If the caller has a non-null class loader, and that loader + // is not this class' loader or an ancestor thereof, then do a + // security check. + if (caller_loader != NULL && ! caller_loader->isAncestorOf(loader)) + s->checkPermission (new RuntimePermission (JvNewStringLatin1 ("getClassLoader"))); + } // The spec requires us to return `null' for primitive classes. In // other cases we have the option of returning `null' for classes @@ -136,13 +154,14 @@ java::lang::Class::getClassLoader (void) java::lang::reflect::Constructor * java::lang::Class::getConstructor (JArray *param_types) { + memberAccessCheck(java::lang::reflect::Member::PUBLIC); + jstring partial_sig = getSignature (param_types, true); jint hash = partial_sig->hashCode (); int i = isPrimitive () ? 0 : method_count; while (--i >= 0) { - // FIXME: access checks. if (_Jv_equalUtf8Consts (methods[i].name, init_name) && _Jv_equal (methods[i].signature, partial_sig, hash)) { @@ -163,7 +182,7 @@ java::lang::Class::getConstructor (JArray *param_types) JArray * java::lang::Class::_getConstructors (jboolean declared) { - // FIXME: this method needs access checks. + memberAccessCheck(java::lang::reflect::Member::PUBLIC); int numConstructors = 0; int max = isPrimitive () ? 0 : method_count; @@ -206,13 +225,14 @@ java::lang::Class::_getConstructors (jboolean declared) java::lang::reflect::Constructor * java::lang::Class::getDeclaredConstructor (JArray *param_types) { + memberAccessCheck(java::lang::reflect::Member::DECLARED); + jstring partial_sig = getSignature (param_types, true); jint hash = partial_sig->hashCode (); int i = isPrimitive () ? 0 : method_count; while (--i >= 0) { - // FIXME: access checks. if (_Jv_equalUtf8Consts (methods[i].name, init_name) && _Jv_equal (methods[i].signature, partial_sig, hash)) { @@ -256,9 +276,7 @@ java::lang::Class::getField (jstring name, jint hash) java::lang::reflect::Field * java::lang::Class::getDeclaredField (jstring name) { - java::lang::SecurityManager *s = java::lang::System::getSecurityManager(); - if (s != NULL) - s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED); + memberAccessCheck(java::lang::reflect::Member::DECLARED); int hash = name->hashCode(); for (int i = 0; i < field_count; i++) { @@ -277,9 +295,7 @@ java::lang::Class::getDeclaredField (jstring name) JArray * java::lang::Class::getDeclaredFields (void) { - java::lang::SecurityManager *s = java::lang::System::getSecurityManager(); - if (s != NULL) - s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED); + memberAccessCheck(java::lang::reflect::Member::DECLARED); JArray *result = (JArray *) JvNewObjectArray (field_count, &java::lang::reflect::Field::class$, NULL); @@ -361,6 +377,8 @@ java::lang::Class::_getDeclaredMethod (jstring name, JArray * java::lang::Class::getDeclaredMethods (void) { + memberAccessCheck(java::lang::reflect::Member::DECLARED); + int numMethods = 0; int max = isPrimitive () ? 0 : method_count; int i; @@ -424,7 +442,7 @@ java::lang::Class::getClasses (void) JArray * java::lang::Class::getDeclaredClasses (void) { - checkMemberAccess (java::lang::reflect::Member::DECLARED); + memberAccessCheck (java::lang::reflect::Member::DECLARED); // Until we have inner classes, it always makes sense to return an // empty array. JArray *result @@ -482,9 +500,7 @@ java::lang::Class::_getFields (JArray *result, JArray * java::lang::Class::getFields (void) { - // FIXME: security checking. - - using namespace java::lang::reflect; + memberAccessCheck(java::lang::reflect::Member::PUBLIC); int count = _getFields (NULL, 0); @@ -518,7 +534,6 @@ java::lang::Class::_getMethod (jstring name, JArray *param_types) int i = klass->isPrimitive () ? 0 : klass->method_count; while (--i >= 0) { - // FIXME: access checks. if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len) && (klass->methods[i].accflags @@ -642,7 +657,7 @@ java::lang::Class::getMethods (void) { using namespace java::lang::reflect; - // FIXME: security checks. + memberAccessCheck(Member::PUBLIC); // This will overestimate the size we need. jint count = _getMethods (NULL, 0); @@ -696,12 +711,7 @@ java::lang::Class::isInstance (jobject obj) jobject java::lang::Class::newInstance (void) { - // FIXME: do accessibility checks here. There currently doesn't - // seem to be any way to do these. - // FIXME: we special-case one check here just to pass a Plum Hall - // test. Once access checking is implemented, remove this. - if (this == &java::lang::Class::class$) - throw new java::lang::IllegalAccessException; + memberAccessCheck(java::lang::reflect::Member::PUBLIC); if (isPrimitive () || isInterface () @@ -1744,7 +1754,26 @@ _Jv_MakeVTable (jclass klass) { for (int i = 0; i < klass->vtable_method_count; ++i) if (! flags[i]) - // FIXME: messsage. - throw new java::lang::AbstractMethodError (); + { + using namespace java::lang; + while (klass != NULL) + { + for (int j = 0; j < klass->method_count; ++j) + { + if (klass->methods[i].index == i) + { + StringBuffer *buf = new StringBuffer (); + buf->append (_Jv_NewStringUtf8Const (klass->methods[i].name)); + buf->append ((jchar) ' '); + buf->append (_Jv_NewStringUtf8Const (klass->methods[i].signature)); + throw new AbstractMethodError (buf->toString ()); + } + } + klass = klass->getSuperclass (); + } + // Couldn't find the name, which is weird. + // But we still must throw the error. + throw new AbstractMethodError (); + } } } diff --git a/libjava/java/lang/reflect/Field.java b/libjava/java/lang/reflect/Field.java index 6410a7f..b54a103 100644 --- a/libjava/java/lang/reflect/Field.java +++ b/libjava/java/lang/reflect/Field.java @@ -1,4 +1,4 @@ -/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation This file is part of libgcj. @@ -12,15 +12,6 @@ package java.lang.reflect; * @author Per Bothner * @date September 1998; February 1999. */ -/* Status: Mostly implemented. - * However, access checks are not implemented. See natField.cc for - * _Jv_CheckFieldAccessibility as well as the missing getCaller. - * Note that the idea is to have to compiler convert calls to - * setXXX(...) and getXXX(...) to setXXX(CALLER, ...) and getXXX(CALLER, ...), - * where CALLER is reference to the class that contains the calls to - * setXXX or getXXX. This is easy for the compiler, and replaces - * expensive stack and table searching with a constant. - */ public final class Field extends AccessibleObject implements Member { @@ -39,12 +30,12 @@ public final class Field extends AccessibleObject implements Member } public boolean equals (Object fld) - { - if (! (fld instanceof Field)) - return false; - Field f = (Field) fld; - return declaringClass == f.declaringClass && offset == f.offset; - } + { + if (! (fld instanceof Field)) + return false; + Field f = (Field) fld; + return declaringClass == f.declaringClass && offset == f.offset; + } public Class getDeclaringClass () { @@ -62,11 +53,6 @@ public final class Field extends AccessibleObject implements Member return (declaringClass.hashCode() ^ offset); } - // The idea is that the compiler will magically translate - // fld.getShort(obj) to fld.getShort(THISCLASS, obj). - // This makes checking assessiblity more efficient, - // since we don't have to do any stack-walking. - public boolean getBoolean (Object obj) throws IllegalArgumentException, IllegalAccessException { diff --git a/libjava/java/lang/reflect/natArray.cc b/libjava/java/lang/reflect/natArray.cc index 7875122..9fa2ef7 100644 --- a/libjava/java/lang/reflect/natArray.cc +++ b/libjava/java/lang/reflect/natArray.cc @@ -1,6 +1,6 @@ // natField.cc - Implementation of java.lang.reflect.Field native methods. -/* Copyright (C) 1999, 2000, 2001 Free Software Foundation +/* Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation This file is part of libgcj. @@ -15,6 +15,7 @@ details. */ #include #include #include +#include #include #include #include @@ -38,8 +39,8 @@ java::lang::reflect::Array::newInstance (jclass componentType, jint length) return _Jv_NewPrimArray (componentType, length); } else + // FIXME: class loader? return JvNewObjectArray (length, componentType, NULL); - } jobject @@ -52,10 +53,26 @@ java::lang::reflect::Array::newInstance (jclass componentType, jint* dims = elements (dimensions); if (ndims == 1) return newInstance (componentType, dims[0]); + + gnu::gcj::runtime::StackTrace *t + = new gnu::gcj::runtime::StackTrace(4); + Class *caller = NULL; + ClassLoader *caller_loader = NULL; + try + { + for (int i = 1; !caller; i++) + { + caller = t->classAt (i); + } + caller_loader = caller->getClassLoaderInternal(); + } + catch (::java::lang::ArrayIndexOutOfBoundsException *e) + { + } + jclass arrayType = componentType; - for (int i = 0; i < ndims; i++) // FIXME 2nd arg should - // be "current" loader - arrayType = _Jv_GetArrayClass (arrayType, 0); + for (int i = 0; i < ndims; i++) + arrayType = _Jv_GetArrayClass (arrayType, caller_loader); return _Jv_NewMultiArray (arrayType, ndims, dims); } @@ -343,8 +360,10 @@ java::lang::reflect::Array::setBoolean (jobject array, void java::lang::reflect::Array::set (jobject array, jint index, - jobject value, jclass elType) + jobject value, jclass elType) { + // We don't have to call getElementType here, or check INDEX, + // because it was already done in the Java wrapper. if (! _Jv_IsInstanceOf (value, elType)) throw new java::lang::IllegalArgumentException; elements ((jobjectArray) array) [index] = value; diff --git a/libjava/java/lang/reflect/natConstructor.cc b/libjava/java/lang/reflect/natConstructor.cc index 7f90b12..466c754 100644 --- a/libjava/java/lang/reflect/natConstructor.cc +++ b/libjava/java/lang/reflect/natConstructor.cc @@ -1,6 +1,6 @@ // natConstructor.cc - Native code for Constructor class. -/* Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation +/* Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation This file is part of libgcj. @@ -13,6 +13,8 @@ details. */ #include #include +#include +#include #include #include #include @@ -46,6 +48,24 @@ java::lang::reflect::Constructor::newInstance (jobjectArray args) if (parameter_types == NULL) getType (); + gnu::gcj::runtime::StackTrace *t + = new gnu::gcj::runtime::StackTrace(4); + Class *caller = NULL; + try + { + for (int i = 1; !caller; i++) + { + caller = t->classAt (i); + } + } + catch (::java::lang::ArrayIndexOutOfBoundsException *e) + { + } + + if (! isAccessible() && ! _Jv_CheckAccess(caller, declaringClass, + declaringClass->getModifiers())) + throw new java::lang::IllegalAccessException; + using namespace java::lang::reflect; if (Modifier::isAbstract (declaringClass->getModifiers())) throw new InstantiationException; diff --git a/libjava/java/lang/reflect/natField.cc b/libjava/java/lang/reflect/natField.cc index 93e27a2..5f104a9 100644 --- a/libjava/java/lang/reflect/natField.cc +++ b/libjava/java/lang/reflect/natField.cc @@ -1,6 +1,6 @@ // natField.cc - Implementation of java.lang.reflect.Field native methods. -/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation This file is part of libgcj. @@ -15,6 +15,7 @@ details. */ #include #include #include +#include #include #include #include @@ -46,31 +47,36 @@ java::lang::reflect::Field::getType () { jfieldID fld = _Jv_FromReflectedField (this); JvSynchronize sync (declaringClass); - _Jv_ResolveField (fld, declaringClass->getClassLoader ()); + _Jv_ResolveField (fld, declaringClass->getClassLoaderInternal ()); return fld->type; } -static void -_Jv_CheckFieldAccessibility (jfieldID /*fld*/, jclass /*caller*/) -{ -#if 0 - if (caller == NULL) - caller = getCaller(); -#endif -#if 0 - _Jv_ushort flags = fld->getModifiers(); - check accesss; -#endif -} - static void* getAddr (java::lang::reflect::Field* field, jclass caller, jobject obj) { + // FIXME: we know CALLER is NULL here. At one point we planned to + // have the compiler insert the caller as a hidden argument in some + // calls. However, we never implemented that, so we have to find + // the caller by hand instead. + gnu::gcj::runtime::StackTrace *t + = new gnu::gcj::runtime::StackTrace(4); + try + { + for (int i = 1; !caller; i++) + { + caller = t->classAt (i); + } + } + catch (::java::lang::ArrayIndexOutOfBoundsException *e) + { + } + jfieldID fld = _Jv_FromReflectedField (field); _Jv_ushort flags = fld->getModifiers(); - if (! (flags & java::lang::reflect::Modifier::PUBLIC) - && ! field->isAccessible ()) - _Jv_CheckFieldAccessibility (fld, caller); + if (! field->isAccessible () + && ! _Jv_CheckAccess (caller, field->getDeclaringClass(), flags)) + throw new java::lang::IllegalAccessException; + if (flags & java::lang::reflect::Modifier::STATIC) { jclass fldClass = field->getDeclaringClass (); diff --git a/libjava/java/lang/reflect/natMethod.cc b/libjava/java/lang/reflect/natMethod.cc index c0f7077..7f391f9 100644 --- a/libjava/java/lang/reflect/natMethod.cc +++ b/libjava/java/lang/reflect/natMethod.cc @@ -1,6 +1,6 @@ // natMethod.cc - Native code for Method class. -/* Copyright (C) 1998, 1999, 2000, 2001 , 2002 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001 , 2002, 2003 Free Software Foundation This file is part of libgcj. @@ -30,6 +30,7 @@ details. */ #include #include #include +#include #include #include #include @@ -142,19 +143,33 @@ java::lang::reflect::Method::invoke (jobject obj, jobjectArray args) if (parameter_types == NULL) getType (); + gnu::gcj::runtime::StackTrace *t + = new gnu::gcj::runtime::StackTrace(4); + Class *caller = NULL; + try + { + for (int i = 1; !caller; i++) + { + caller = t->classAt (i); + } + } + catch (::java::lang::ArrayIndexOutOfBoundsException *e) + { + } + jmethodID meth = _Jv_FromReflectedMethod (this); + jclass klass; if (! java::lang::reflect::Modifier::isStatic(meth->accflags)) { - jclass k = obj ? obj->getClass() : NULL; if (! obj) throw new java::lang::NullPointerException; - if (! declaringClass->isAssignableFrom(k)) + klass = obj->getClass(); + if (! declaringClass->isAssignableFrom(klass)) throw new java::lang::IllegalArgumentException; - // FIXME: access checks. // Find the possibly overloaded method based on the runtime type // of the object. - meth = _Jv_LookupDeclaredMethod (k, meth->name, meth->signature); + meth = _Jv_LookupDeclaredMethod (klass, meth->name, meth->signature); } else { @@ -162,8 +177,12 @@ java::lang::reflect::Method::invoke (jobject obj, jobjectArray args) // here and not in _Jv_CallAnyMethodA because JNI initializes a // class whenever a method lookup is done. _Jv_InitClass (declaringClass); + klass = declaringClass; } + if (! isAccessible() && ! _Jv_CheckAccess(caller, klass, meth->accflags)) + throw new IllegalArgumentException; + return _Jv_CallAnyMethodA (obj, return_type, meth, false, parameter_types, args); } @@ -207,7 +226,7 @@ java::lang::reflect::Method::getType () jclass *elts = elements (exception_types); for (int i = 0; i < count; ++i) elts[i] = _Jv_FindClass (method->throws[i], - declaringClass->getClassLoader ()); + declaringClass->getClassLoaderInternal ()); } void @@ -218,7 +237,7 @@ _Jv_GetTypesFromSignature (jmethodID method, { _Jv_Utf8Const* sig = method->signature; - java::lang::ClassLoader *loader = declaringClass->getClassLoader(); + java::lang::ClassLoader *loader = declaringClass->getClassLoaderInternal(); char *ptr = sig->data; int numArgs = 0; /* First just count the number of parameters. */ @@ -344,19 +363,11 @@ _Jv_CallAnyMethodA (jobject obj, jclass *paramelts = elements (parameter_types); - // FIXME: at some point the compiler is going to add extra arguments - // to some functions. In particular we are going to do this for - // handling access checks in reflection. We must add these hidden - // arguments here. - // Special case for the `this' argument of a constructor. Note that // the JDK 1.2 docs specify that the new object must be allocated // before argument conversions are done. if (is_constructor) - { - // FIXME: must special-case String, arrays, maybe others here. - obj = JvAllocObject (return_type); - } + obj = JvAllocObject (return_type); const int size_per_arg = sizeof(jvalue); ffi_cif cif; @@ -488,8 +499,6 @@ _Jv_CallAnyMethodA (jobject obj, JArray *parameter_types, jobjectArray args) { - // FIXME: access checks. - if (parameter_types->length == 0 && args == NULL) { // The JDK accepts this, so we do too. diff --git a/libjava/jni.cc b/libjava/jni.cc index 81ef0f7..eace628 100644 --- a/libjava/jni.cc +++ b/libjava/jni.cc @@ -491,7 +491,7 @@ static jclass java::lang::ClassLoader *loader = NULL; if (env->klass != NULL) - loader = env->klass->getClassLoader (); + loader = env->klass->getClassLoaderInternal (); if (loader == NULL) { @@ -1189,7 +1189,7 @@ static jfieldID // FIXME: what if field_class == NULL? - java::lang::ClassLoader *loader = clazz->getClassLoader (); + java::lang::ClassLoader *loader = clazz->getClassLoaderInternal (); while (clazz != NULL) { // We acquire the class lock so that fields aren't resolved diff --git a/libjava/prims.cc b/libjava/prims.cc index 8d9cc6d..9f84773 100644 --- a/libjava/prims.cc +++ b/libjava/prims.cc @@ -1,6 +1,6 @@ // prims.cc - Code for core of runtime environment. -/* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation This file is part of libgcj. @@ -1137,3 +1137,21 @@ _Jv_remJ (jlong dividend, jlong divisor) return dividend % divisor; } + + + +// Return true if SELF_KLASS can access a field or method in +// OTHER_KLASS. The field or method's access flags are specified in +// FLAGS. +jboolean +_Jv_CheckAccess (jclass self_klass, jclass other_klass, jint flags) +{ + using namespace java::lang::reflect; + return ((self_klass == other_klass) + || ((flags & Modifier::PUBLIC) != 0) + || (((flags & Modifier::PROTECTED) != 0) + && other_klass->isAssignableFrom (self_klass)) + || (((flags & Modifier::PRIVATE) == 0) + && _Jv_ClassNameSamePackage (self_klass->name, + other_klass->name))); +} diff --git a/libjava/resolve.cc b/libjava/resolve.cc index 7cf0b0a..d79affe 100644 --- a/libjava/resolve.cc +++ b/libjava/resolve.cc @@ -166,15 +166,7 @@ _Jv_ResolvePoolEntry (jclass klass, int index) if (! _Jv_equalUtf8Consts (field->name, field_name)) continue; - // now, check field access. - - if ( (cls == klass) - || ((field->flags & Modifier::PUBLIC) != 0) - || (((field->flags & Modifier::PROTECTED) != 0) - && cls->isAssignableFrom (klass)) - || (((field->flags & Modifier::PRIVATE) == 0) - && _Jv_ClassNameSamePackage (cls->name, - klass->name))) + if (_Jv_CheckAccess (klass, cls, field->flags)) { /* resove the field using the class' own loader if necessary */ @@ -347,20 +339,10 @@ _Jv_SearchMethodInClass (jclass cls, jclass klass, method_signature))) continue; - if (cls == klass - || ((method->accflags & Modifier::PUBLIC) != 0) - || (((method->accflags & Modifier::PROTECTED) != 0) - && cls->isAssignableFrom (klass)) - || (((method->accflags & Modifier::PRIVATE) == 0) - && _Jv_ClassNameSamePackage (cls->name, - klass->name))) - { - return method; - } + if (_Jv_CheckAccess (klass, cls, method->accflags)) + return method; else - { - throw new java::lang::IllegalAccessError; - } + throw new java::lang::IllegalAccessError; } return 0; } -- cgit v1.1