* Removed all Id tags.
[cacao.git] / src / vm / access.c
index fa36e0fd9205a6531799f8e25a8285fb4a346f11..c8d1b68fb8779d6ffb7f9c0a35780774f31fa2d7 100644 (file)
@@ -1,6 +1,6 @@
-/* vm/access.c - checking access rights
+/* src/vm/access.c - checking access rights
 
-   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
    J. Wenninger, Institut f. Computersprachen - TU Wien
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Contact: cacao@cacaojvm.org
-
-   Authors: Edwin Steiner
-
-   Changes:
-
-   $Id: access.c 5846 2006-10-28 13:02:19Z edwin $
-
 */
 
 
 #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/class.h"
 #include "vm/exceptions.h"
-#include "vm/stringlocal.h"
 
+#include "vm/jit/stacktrace.h"
+
+#include "vmcore/class.h"
+#include "vmcore/field.h"
+#include "vmcore/method.h"
 
-/****************************************************************************/
-/* ACCESS CHECKS                                                            */
-/****************************************************************************/
 
 /* access_is_accessible_class **************************************************
  
@@ -74,19 +71,34 @@ 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 */
-       return false;
-}
+#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;
+}
 
 
 /* access_is_accessible_member *************************************************
@@ -118,45 +130,148 @@ 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 */
+
        if (memberflags & ACC_PRIVATE)
                return (referer == declarer);
 
        /* {the member is protected or package private} */
 
-       /* protected and package private members are accessible in the same package */
-       if (SAME_PACKAGE(referer,declarer))
+       /* protected and package private members are accessible in the
+          same package */
+
+       if (SAME_PACKAGE(referer, declarer))
                return true;
 
        /* package private members are not accessible outside the package */
+
        if (!(memberflags & ACC_PROTECTED))
                return false;
 
        /* {the member is protected and declarer is in another package} */
 
-       /* a necessary condition for access is that referer is a subclass of declarer */
+       /* a necessary condition for access is that referer is a subclass
+          of 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_caller *********************************************************
+/* 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:
+
+                                          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_field(fieldinfo *f, 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 ((f->class->flags & ACC_PUBLIC) && (f->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, 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:
 
@@ -173,33 +288,57 @@ bool access_is_accessible_member(classinfo *referer, classinfo *declarer,
    
 *******************************************************************************/
 
-bool access_check_caller(classinfo *declarer, s4 memberflags, s4 calldepth)
+bool access_check_method(methodinfo *m, 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 ((m->class->flags & ACC_PUBLIC) && (m->flags & ACC_PUBLIC))
                return true;
 
        /* get the caller's class */
 
        oa = stacktrace_getClassContext();
-       if (!oa)
+
+       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_class(callerclass, declarer)
-               || !access_is_accessible_member(callerclass, declarer, memberflags))
-       {
-               *exceptionptr =
-                       new_exception(string_java_lang_IllegalAccessException);
+       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;
        }
 
@@ -208,6 +347,7 @@ bool access_check_caller(classinfo *declarer, s4 memberflags, s4 calldepth)
        return true;
 }
 
+
 /*
  * These are local overrides for various environment variables in Emacs.
  * Please do not remove this and leave it at the end of the file, where