This is the mail archive of the java@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Symbol table resolution


Properly enforcing access rules in libgcj causes problems in that
compiler-generated code sometimes wants to access private methods.

This patch uses a single bit in the signature pointer to indicate that
this is a compiler-generated access, so we should not perform any
access checks.  Encoding the bit in this way isn't very nice, but it
is fast and backward compatible.

The compiler part of this patch will be sent separately in a plain
wrapper...

Andrew.


2006-06-07  Andrew Haley  <aph@redhat.com>

	* include/jvm.h (_Jv_Linker::maybe_adjust_signature): New.
	(_Jv_Linker::uaddr): New.
	* link.cc (resolve_pool_entry): Call search_method_in_superclasses
	instead of an open-coded loop around search_method_in_class.
	(search_method_in_class): Add a new arg, check_perms.
	(search_method_in_superclasses): New.
	(link_symbol_table): Call maybe_adjust_signature() to extract the
	least significnt bit of the signature pointer.  Do this three
	times, for instace method calls, static methods, and interfaces.
	Call search_method_in_superclasses() instead of
	_Jv_LookupDeclaredMethod.
	(typedef uaddr): Delete.
	
Index: link.cc
===================================================================
--- link.cc	(revision 114388)
+++ link.cc	(working copy)
@@ -55,8 +55,6 @@
 
 using namespace gcj;
 
-typedef unsigned int uaddr __attribute__ ((mode (pointer)));
-
 template<typename T>
 struct aligner
 {
@@ -461,19 +459,11 @@
 	      goto end_of_method_search;
 	  }
 
-	// Finally, search superclasses. 
-	for (jclass cls = owner->getSuperclass (); cls != 0; 
-	     cls = cls->getSuperclass ())
-	  {
-	    the_method = search_method_in_class (cls, klass, method_name,
-						 method_signature);
-	    if (the_method != 0)
-	      {
-		found_class = cls;
-		break;
-	      }
-	  }
-
+	// Finally, search superclasses.
+	the_method = (search_method_in_superclasses 
+		      (owner->getSuperclass (), klass, method_name, 
+		       method_signature, &found_class));
+	
       end_of_method_search:
     
 	// FIXME: if (cls->loader != klass->loader), then we
@@ -534,11 +524,12 @@
 }
 
 // Find a method declared in the cls that is referenced from klass and
-// perform access checks.
+// perform access checks if CHECK_PERMS is true.
 _Jv_Method *
 _Jv_Linker::search_method_in_class (jclass cls, jclass klass, 
 				    _Jv_Utf8Const *method_name, 
-				    _Jv_Utf8Const *method_signature)
+				    _Jv_Utf8Const *method_signature,
+				    bool check_perms)
 {
   using namespace java::lang::reflect;
 
@@ -551,7 +542,7 @@
 				    method_signature)))
 	continue;
 
-      if (_Jv_CheckAccess (klass, cls, method->accflags))
+      if (!check_perms || _Jv_CheckAccess (klass, cls, method->accflags))
 	return method;
       else
 	{
@@ -568,6 +559,30 @@
   return 0;
 }
 
+// Like search_method_in_class, but work our way up the superclass
+// chain.
+_Jv_Method *
+_Jv_Linker::search_method_in_superclasses (jclass cls, jclass klass, 
+					   _Jv_Utf8Const *method_name, 
+					   _Jv_Utf8Const *method_signature,
+					   jclass *found_class, bool check_perms)
+{
+  _Jv_Method *the_method = NULL;
+
+  for ( ; cls != 0; cls = cls->getSuperclass ())
+    {
+      the_method = search_method_in_class (cls, klass, method_name,
+					   method_signature, check_perms);
+      if (the_method != 0)
+	{
+	  if (found_class)
+	    *found_class = cls;
+	  break;
+	}
+    }
+  
+  return the_method;
+}
 
 #define INITIAL_IOFFSETS_LEN 4
 #define INITIAL_IFACES_LEN 4
@@ -1076,6 +1091,8 @@
       _Jv_Method *meth = NULL;            
 
       _Jv_Utf8Const *signature = sym.signature;
+      uaddr special;
+      maybe_adjust_signature (signature, special);
 
       if (target_class == NULL)
 	throw new java::lang::NoClassDefFoundError 
@@ -1101,8 +1118,15 @@
 	  // it out now.
 	  wait_for_state(target_class, JV_STATE_PREPARED);
 
-	  meth = _Jv_LookupDeclaredMethod(target_class, sym.name, 
-					  sym.signature);
+	  try
+	    {
+	      meth = (search_method_in_superclasses 
+		      (target_class, klass, sym.name, signature, 
+		       NULL, special == 0));
+	    }
+	  catch (::java::lang::IllegalAccessError *e)
+	    {
+	    }
 
 	  // Every class has a throwNoSuchMethodErrorIndex method that
 	  // it inherits from java.lang.Object.  Find its vtable
@@ -1158,7 +1182,7 @@
 	try
 	  {
 	    the_field = find_field (klass, target_class, &found_class,
-				    sym.name, sym.signature);
+				    sym.name, signature);
 	    if ((the_field->flags & java::lang::reflect::Modifier::STATIC))
 	      throw new java::lang::IncompatibleClassChangeError;
 	    else
@@ -1185,7 +1209,10 @@
         _Jv_FindClassNoException (sym.class_name, klass->loader);
 
       _Jv_Method *meth = NULL;            
+
       _Jv_Utf8Const *signature = sym.signature;
+      uaddr special;
+      maybe_adjust_signature (signature, special);
 
       // ??? Setting this pointer to null will at least get us a
       // NullPointerException
@@ -1193,7 +1220,7 @@
 
       // If the target class is missing we prepare a function call
       // that throws a NoClassDefFoundError and store the address of
-      // that newly prepare method in the atable. The user can run
+      // that newly prepared method in the atable. The user can run
       // code in classes where the missing class is part of the
       // execution environment as long as it is never referenced.
       if (target_class == NULL)
@@ -1219,8 +1246,15 @@
 	      throw new VerifyError(sb->toString());
 	    }
 
-	  meth = _Jv_LookupDeclaredMethod(target_class, sym.name, 
-					  sym.signature);
+	  try
+	    {
+	      meth = (search_method_in_superclasses 
+		      (target_class, klass, sym.name, signature, 
+		       NULL, special == 0));
+	    }
+	  catch (::java::lang::IllegalAccessError *e)
+	    {
+	    }
 
 	  if (meth != NULL)
 	    {
@@ -1250,7 +1284,7 @@
 	wait_for_state(target_class, JV_STATE_PREPARED);
 	jclass found_class;
 	_Jv_Field *the_field = find_field (klass, target_class, &found_class,
-					   sym.name, sym.signature);
+					   sym.name, signature);
 	if ((the_field->flags & java::lang::reflect::Modifier::STATIC))
 	  klass->atable->addresses[index] = the_field->u.addr;
 	else
@@ -1270,14 +1304,17 @@
        ++index)
     {
       jclass target_class = _Jv_FindClass (sym.class_name, klass->loader);
+
       _Jv_Utf8Const *signature = sym.signature;
+      uaddr special;
+      maybe_adjust_signature (signature, special);
 
       jclass cls;
       int i;
 
       wait_for_state(target_class, JV_STATE_LOADED);
       bool found = _Jv_getInterfaceMethod (target_class, cls, i,
-					   sym.name, sym.signature);
+					   sym.name, signature);
 
       if (found)
 	{
Index: include/jvm.h
===================================================================
--- include/jvm.h	(revision 114388)
+++ include/jvm.h	(working copy)
@@ -239,6 +239,8 @@
 class _Jv_Linker
 {
 private:
+  typedef unsigned int uaddr __attribute__ ((mode (pointer)));
+
   static _Jv_Field *find_field_helper(jclass, _Jv_Utf8Const *, _Jv_Utf8Const *,
 				      jclass, jclass *);
   static _Jv_Field *find_field(jclass, jclass, jclass *, _Jv_Utf8Const *,
@@ -264,9 +266,32 @@
   static jshort append_partial_itable(jclass, jclass, void **, jshort);
   static _Jv_Method *search_method_in_class (jclass, jclass,
 					     _Jv_Utf8Const *,
-					     _Jv_Utf8Const *);
+					     _Jv_Utf8Const *,
+					     bool check_perms = true);
+  static _Jv_Method *search_method_in_superclasses (jclass cls, jclass klass, 
+						    _Jv_Utf8Const *method_name,
+ 						    _Jv_Utf8Const *method_signature,
+						    jclass *found_class,
+						    bool check_perms = true);
   static void *create_error_method(_Jv_Utf8Const *);
 
+  /* The least significant bit of the signature pointer in a symbol
+     table is set to 1 by the compiler if the reference is "special",
+     i.e. if it is an access to a private field or method.  Extract
+     that bit, clearing it in the address and setting the LSB of
+     SPECIAL accordingly.  */
+  static void maybe_adjust_signature (_Jv_Utf8Const *&s, uaddr &special)
+  {
+    union {
+      _Jv_Utf8Const *signature;
+      uaddr signature_bits;
+    };
+    signature = s;
+    special = signature_bits & 1;
+    signature_bits -= special;
+    s = signature;
+  }  
+
 public:
 
   static bool has_field_p (jclass, _Jv_Utf8Const *);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]