* Removed all Id tags.
[cacao.git] / src / vm / access.c
index 728ea014b5cc8066cfbfabaa8230d12f3049a8c0..c8d1b68fb8779d6ffb7f9c0a35780774f31fa2d7 100644 (file)
@@ -1,9 +1,9 @@
-/* vm/access.c - checking access rights
+/* src/vm/access.c - checking access rights
 
-   Copyright (C) 1996-2005 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
+   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
 
    This file is part of CACAO.
 
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
 
-   Contact: cacao@complang.tuwien.ac.at
+*/
 
-   Authors: Edwin Steiner
 
-   Changes:
+#include "config.h"
 
-   $Id: access.c 2096 2005-03-27 18:57:00Z edwin $
+#include <assert.h>
+#include <string.h>
 
-*/
+#include "vm/types.h"
+
+#include "mm/memory.h"
+
+#include "native/llni.h"
 
-#include <assert.h>
 #include "vm/access.h"
 #include "vm/builtin.h"
+#include "vm/exceptions.h"
 
-/****************************************************************************/
-/* DEBUG HELPERS                                                            */
-/****************************************************************************/
+#include "vm/jit/stacktrace.h"
 
-#ifdef NDEBUG
-#define ACCESS_DEBUG
-#endif
+#include "vmcore/class.h"
+#include "vmcore/field.h"
+#include "vmcore/method.h"
 
-#ifdef ACCESS_DEBUG
-#define ACCESS_ASSERT(cond)  assert(cond)
-#else
-#define ACCESS_ASSERT(cond)
-#endif
 
-/****************************************************************************/
-/* ACCESS CHECKS                                                            */
-/****************************************************************************/
+/* access_is_accessible_class **************************************************
+   Check if a class is accessible from another class
+  
+   IN:
+       referer..........the class containing the reference
+       cls..............the result of resolving the reference
+  
+   RETURN VALUE:
+       true.............access permitted
+       false............access denied
+   
+   NOTE:
+       This function performs the checks listed in section 5.4.4.
+          "Access Control" of "The Java(TM) Virtual Machine Specification,
+          Second Edition".
+
+*******************************************************************************/
 
-/* for documentation see access.h */
-bool
-is_accessible_class(classinfo *referer,classinfo *cls)
+bool access_is_accessible_class(classinfo *referer, classinfo *cls)
 {
-       ACCESS_ASSERT(referer);
-       ACCESS_ASSERT(cls);
+       assert(referer);
+       assert(cls);
+
+       /* Public classes are always accessible. */
+
+       if (cls->flags & ACC_PUBLIC)
+               return true;
+
+       /* A class in the same package is always accessible. */
 
-       /* XXX specially check access to array classes? (vmspec 5.3.3) */
-       
-       /* public classes are always accessible */
-       if ((cls->flags & ACC_PUBLIC) != 0)
+       if (SAME_PACKAGE(referer, cls))
                return true;
 
-       /* a class in the same package is always accessible */
-       if (SAME_PACKAGE(referer,cls))
+#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. */
 
-       /* a non-public class in another package is not accessible */
        return false;
 }
 
-/* for documentation see access.h */
-bool
-is_accessible_member(classinfo *referer,classinfo *declarer,s4 memberflags)
+
+/* access_is_accessible_member *************************************************
+   Check if a field or method is accessible from a given class
+  
+   IN:
+       referer..........the class containing the reference
+       declarer.........the class declaring the member
+       memberflags......the access flags of the member
+  
+   RETURN VALUE:
+       true.............access permitted
+       false............access denied
+
+   NOTE:
+       This function only performs the checks listed in section 5.4.4.
+          "Access Control" of "The Java(TM) Virtual Machine Specification,
+          Second Edition".
+
+          In particular a special condition for protected access with is
+          part of the verification process according to the spec is not
+          checked in this function.
+   
+*******************************************************************************/
+
+bool access_is_accessible_member(classinfo *referer, classinfo *declarer,
+                                                                s4 memberflags)
 {
-       ACCESS_ASSERT(referer);
-       ACCESS_ASSERT(declarer);
-       
-       /* public members are accessible */
-       if ((memberflags & ACC_PUBLIC) != 0)
+       assert(referer);
+       assert(declarer);
+
+       /* 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) != 0)
+
+       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) == 0)
+
+       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 */
-       ACCESS_ASSERT(referer->linked && declarer->linked);
-       if (builtin_isanysubclass(referer,declarer))
+       /* a necessary condition for access is that referer is a subclass
+          of declarer */
+
+       assert((referer->state & CLASS_LINKED) && (declarer->state & CLASS_LINKED));
+
+       if (class_isanysubclass(referer, declarer))
                return true;
 
        return false;
 }
 
+
+/* access_check_field **********************************************************
+   Check if the (indirect) caller has access rights to the specified
+   field.
+  
+   IN:
+       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:
+
+                                          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;
+       }
+
+       /* access granted */
+
+       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