* Removed all Id tags.
[cacao.git] / src / vm / access.c
index 45e8548bcd3d03721ea65e3c8c0a6f421f0a9439..c8d1b68fb8779d6ffb7f9c0a35780774f31fa2d7 100644 (file)
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   $Id: access.c 7441 2007-03-02 23:13:10Z michi $
-
 */
 
 
 #include "config.h"
 
 #include <assert.h>
+#include <string.h>
 
 #include "vm/types.h"
 
+#include "mm/memory.h"
+
+#include "native/llni.h"
+
 #include "vm/access.h"
 #include "vm/builtin.h"
 #include "vm/exceptions.h"
 #include "vm/jit/stacktrace.h"
 
 #include "vmcore/class.h"
+#include "vmcore/field.h"
+#include "vmcore/method.h"
 
 
-/****************************************************************************/
-/* ACCESS CHECKS                                                            */
-/****************************************************************************/
-
 /* access_is_accessible_class **************************************************
  
    Check if a class is accessible from another class
@@ -70,17 +71,31 @@ bool access_is_accessible_class(classinfo *referer, classinfo *cls)
        assert(referer);
        assert(cls);
 
-       /* public classes are always accessible */
+       /* Public classes are always accessible. */
 
        if (cls->flags & ACC_PUBLIC)
                return true;
 
-       /* a class in the same package is always accessible */
+       /* A class in the same package is always accessible. */
 
        if (SAME_PACKAGE(referer, cls))
                return true;
 
-       /* a non-public class in another package is not accessible */
+#if defined(WITH_CLASSPATH_SUN)
+       /* Code for Sun's OpenJDK (see
+          hotspot/src/share/vm/runtime/reflection.cpp
+          (Reflection::verify_class_access)): Allow all accesses from
+          sun/reflect/MagicAccessorImpl subclasses to succeed
+          trivially. */
+
+       /* NOTE: This check must be before checks that could return
+          false. */
+
+       if (class_issubclass(referer, class_sun_reflect_MagicAccessorImpl))
+               return true;
+#endif
+
+       /* A non-public class in another package is not accessible. */
 
        return false;
 }
@@ -115,12 +130,26 @@ bool access_is_accessible_member(classinfo *referer, classinfo *declarer,
 {
        assert(referer);
        assert(declarer);
-       
-       /* public members are accessible */
+
+       /* Public members are accessible. */
 
        if (memberflags & ACC_PUBLIC)
                return true;
 
+#if defined(WITH_CLASSPATH_SUN)
+       /* Code for Sun's OpenJDK (see
+          hotspot/src/share/vm/runtime/reflection.cpp
+          (Reflection::verify_class_access)): Allow all accesses from
+          sun/reflect/MagicAccessorImpl subclasses to succeed
+          trivially. */
+
+       /* NOTE: This check must be before checks that could return
+          false. */
+
+       if (class_issubclass(referer, class_sun_reflect_MagicAccessorImpl))
+               return true;
+#endif
+
        /* {declarer is not an interface} */
 
        /* private members are only accessible by the class itself */
@@ -148,20 +177,20 @@ bool access_is_accessible_member(classinfo *referer, classinfo *declarer,
 
        assert((referer->state & CLASS_LINKED) && (declarer->state & CLASS_LINKED));
 
-       if (builtin_isanysubclass(referer, declarer))
+       if (class_isanysubclass(referer, declarer))
                return true;
 
        return false;
 }
 
 
-/* access_check_member *********************************************************
+/* access_check_field **********************************************************
  
-   Check if the (indirect) caller has access rights to a member.
+   Check if the (indirect) caller has access rights to the specified
+   field.
   
    IN:
-       declarer.........the class declaring the member
-       memberflags......the access flags of the member
+       f................the field to check
           calldepth........number of callers to ignore
                            For example if the stacktrace looks like this:
 
@@ -178,14 +207,17 @@ bool access_is_accessible_member(classinfo *referer, classinfo *declarer,
    
 *******************************************************************************/
 
-bool access_check_member(classinfo *declarer, s4 memberflags, s4 calldepth)
+bool access_check_field(fieldinfo *f, s4 calldepth)
 {
-       java_objectarray *oa;
-       classinfo        *callerclass;
+       java_handle_objectarray_t *oa;
+       classinfo                 *callerclass;
+       char                      *msg;
+       s4                         msglen;
+       utf                       *u;
 
        /* if everything is public, there is nothing to check */
 
-       if ((declarer->flags & ACC_PUBLIC) && (memberflags & ACC_PUBLIC))
+       if ((f->class->flags & ACC_PUBLIC) && (f->flags & ACC_PUBLIC))
                return true;
 
        /* get the caller's class */
@@ -195,14 +227,118 @@ bool access_check_member(classinfo *declarer, s4 memberflags, s4 calldepth)
        if (oa == NULL)
                return false;
 
-       assert(calldepth >= 0 && calldepth < oa->header.size);
+       assert(calldepth >= 0 && calldepth < LLNI_array_size(oa));
 
        callerclass = (classinfo *) oa->data[calldepth];
 
        /* check access rights */
 
-       if (!access_is_accessible_member(callerclass, declarer, memberflags)) {
-               exceptions_throw_illegalaccessexception(callerclass);
+       if (!access_is_accessible_member(callerclass, f->class, f->flags)) {
+               msglen =
+                       utf_bytes(f->class->name) +
+                       strlen(".") +
+                       utf_bytes(f->name) +
+                       strlen(" not accessible from ") +
+                       utf_bytes(callerclass->name) +
+                       strlen("0");
+
+               msg = MNEW(char, msglen);
+
+               utf_copy_classname(msg, f->class->name);
+               strcat(msg, ".");
+               utf_cat_classname(msg, f->name);
+               strcat(msg, " not accessible from ");
+               utf_cat_classname(msg, callerclass->name);
+
+               u = utf_new_char(msg);
+
+               MFREE(msg, char, msglen);
+               
+               exceptions_throw_illegalaccessexception(u);
+
+               return false;
+       }
+
+       /* access granted */
+
+       return true;
+}
+
+
+/* access_check_method *********************************************************
+   Check if the (indirect) caller has access rights to the specified
+   method.
+  
+   IN:
+       m................the method to check
+          calldepth........number of callers to ignore
+                           For example if the stacktrace looks like this:
+
+                                          java.lang.reflect.Method.invokeNative (Native Method)
+                                  [0] java.lang.reflect.Method.invoke (Method.java:329)
+                                  [1] <caller>
+
+                                       you must specify 1 so the access rights of <caller> 
+                                               are checked.
+  
+   RETURN VALUE:
+       true.............access permitted
+       false............access denied, an exception has been thrown
+   
+*******************************************************************************/
+
+bool access_check_method(methodinfo *m, s4 calldepth)
+{
+       java_handle_objectarray_t *oa;
+       classinfo                 *callerclass;
+       char                      *msg;
+       s4                         msglen;
+       utf                       *u;
+
+       /* if everything is public, there is nothing to check */
+
+       if ((m->class->flags & ACC_PUBLIC) && (m->flags & ACC_PUBLIC))
+               return true;
+
+       /* get the caller's class */
+
+       oa = stacktrace_getClassContext();
+
+       if (oa == NULL)
+               return false;
+
+       assert(calldepth >= 0 && calldepth < LLNI_array_size(oa));
+
+       callerclass = (classinfo *) oa->data[calldepth];
+
+       /* check access rights */
+
+       if (!access_is_accessible_member(callerclass, m->class, m->flags)) {
+               msglen =
+                       utf_bytes(m->class->name) +
+                       strlen(".") +
+                       utf_bytes(m->name) +
+                       utf_bytes(m->descriptor) +
+                       strlen(" not accessible from ") +
+                       utf_bytes(callerclass->name) +
+                       strlen("0");
+
+               msg = MNEW(char, msglen);
+
+               utf_copy_classname(msg, m->class->name);
+               strcat(msg, ".");
+               utf_cat_classname(msg, m->name);
+               utf_cat_classname(msg, m->descriptor);
+               strcat(msg, " not accessible from ");
+               utf_cat_classname(msg, callerclass->name);
+
+               u = utf_new_char(msg);
+
+               MFREE(msg, char, msglen);
+               
+               exceptions_throw_illegalaccessexception(u);
+
                return false;
        }