-/* 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