This is the mail archive of the java-patches@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]

[gcjx] Patch: FYI: verifier bug fix


I'm checking this in on the gcjx branch.

This is a verifier bug fix from the trunk, ported to the gcjx
verifier.

Tom

Index: ChangeLog
from  Tom Tromey  <tromey@redhat.com>

	* bytecode/verify.cc (EITHER): New constant.
	(type::compatible): Handle EITHER.
	(type::equals): New method.
	(check_field_constant): Added 'putfield' argument.
	(verify_instructions_0): Update 'putfield' handling.
	* verify.h (vfy_fail): Fixed indentation.
	(vfy_class_has_field_p): New function.

Index: verify.h
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/Attic/verify.h,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 verify.h
--- verify.h 13 Jan 2005 03:18:33 -0000 1.1.2.1
+++ verify.h 27 Mar 2005 02:37:26 -0000
@@ -1,5 +1,5 @@
 /* Declarations to interface gcj with bytecode verifier.
-   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -200,6 +200,16 @@
   return const_cast<char *> (pool->get_class (index).c_str ());
 }
 
+// Return true if the class declares a field with the given name.  The
+// type of the field doesn't matter.
+inline bool vfy_class_has_field_p (vfy_jclass type, vfy_string name)
+{
+  std::set<model_field *> result;
+  model_class *klass = assert_cast<model_class *> (type);
+  klass->find_members (name, result, klass, klass);
+  return ! result.empty ();
+}
+
 inline vfy_string vfy_make_string (const char *s, int len)
 {
   char *r = new char[len + 1];
@@ -305,7 +315,8 @@
   if (pc == -1)
     throw method->block->error ("verification failed in method %1: %u2")
       % method->method % message;
-  throw method->block->error ("verification failed at PC %u1 in method %2: %u3")
+  throw method->block->error ("verification failed at PC %u1 "
+			      "in method %2: %u3")
     % pc % method->method % message;
 }
 
Index: bytecode/verify.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/bytecode/Attic/verify.cc,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 verify.cc
--- bytecode/verify.cc 13 Jan 2005 03:18:34 -0000 1.1.2.1
+++ bytecode/verify.cc 27 Mar 2005 02:37:27 -0000
@@ -1,6 +1,6 @@
 // verify.cc - verify bytecode
 
-/* Copyright (C) 2001, 2002, 2003, 2004  Free Software Foundation
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -554,10 +554,12 @@
     // This is used in two situations.
     //
     // First, when constructing a new object, it is the PC of the
-    // 'new' instruction which created the object.  We use the special
-    // value UNINIT to mean that this is uninitialized, and the
-    // special value SELF for the case where the current method is
-    // itself the <init> method.
+    // `new' instruction which created the object.  We use the special
+    // value UNINIT to mean that this is uninitialized.  The special
+    // value SELF is used for the case where the current method is
+    // itself the <init> method.  the special value EITHER is used
+    // when we may optionally allow either an uninitialized or
+    // initialized reference to match.
     //
     // Second, when the key is return_address_type, this holds the PC
     // of the instruction following the 'jsr'.
@@ -565,6 +567,7 @@
 
     static const int UNINIT = -2;
     static const int SELF = -1;
+    static const int EITHER = -3;
 
     // Basic constructor.
     type ()
@@ -711,23 +714,51 @@
       if (k.klass == NULL)
 	verifier->verify_fail ("internal error in type::compatible ()");
 
-      // An initialized type and an uninitialized type are not
-      // compatible.
-      if (isinitialized () != k.isinitialized ())
-	return false;
-
-      // Two uninitialized objects are compatible if either:
-      // * The PCs are identical, or
-      // * One PC is UNINIT.
-      if (! isinitialized ())
+      // Handle the special 'EITHER' case, which is only used in a
+      // special case of 'putfield'.  Note that we only need to handle
+      // this on the LHS of a check.
+      if (! isinitialized () && pc == EITHER)
 	{
-	  if (pc != k.pc && pc != UNINIT && k.pc != UNINIT)
+	  // If the RHS is uninitialized, it must be an uninitialized
+	  // 'this'.
+	  if (! k.isinitialized () && k.pc != SELF)
 	    return false;
 	}
+      else if (isinitialized () != k.isinitialized ())
+	{
+	  // An initialized type and an uninitialized type are not
+	  // otherwise compatible.
+	  return false;
+	}
+      else
+	{
+	  // Two uninitialized objects are compatible if either:
+	  // * The PCs are identical, or
+	  // * One PC is UNINIT.
+	  if (! isinitialized ())
+	    {
+	      if (pc != k.pc && pc != UNINIT && k.pc != UNINIT)
+		return false;
+	    }
+	}
 
       return klass->compatible(k.klass, verifier);
     }
 
+    bool equals (const type &other, _Jv_BytecodeVerifier *vfy)
+    {
+      // Only works for reference types.
+      if ((key != reference_type
+	   && key != uninitialized_reference_type)
+	  || (other.key != reference_type
+	      && other.key != uninitialized_reference_type))
+	return false;
+      // Only for single-valued types.
+      if (klass->ref_next || other.klass->ref_next)
+	return false;
+      return klass->equals (other.klass, vfy);
+    }
+
     bool isvoid () const
     {
       return key == void_type;
@@ -1945,7 +1976,8 @@
   }
 
   // Return field's type, compute class' type if requested.
-  type check_field_constant (int index, type *class_type = NULL)
+  type check_field_constant (int index, type *class_type = NULL,
+			     bool putfield = false)
   {
     vfy_string name, field_type;
     type ct = handle_field_or_method (index,
@@ -1953,10 +1985,30 @@
 				      &name, &field_type);
     if (class_type)
       *class_type = ct;
+    type result;
     const char *b = vfy_string_bytes (field_type);
     if (b[0] == '[' || b[0] == 'L')
-      return type (field_type, this);
-    return get_type_val_for_signature (b[0]);
+      result = type (field_type, this);
+    else
+      result = get_type_val_for_signature (b[0]);
+
+    // We have an obscure special case here: we can use `putfield' on
+    // a field declared in this class, even if `this' has not yet been
+    // initialized.
+    if (putfield
+	&& ! current_state->this_type.isinitialized ()
+	&& current_state->this_type.pc == type::SELF
+	&& current_state->this_type.equals (ct, this)
+	// We don't look at the signature, figuring that if it is
+	// wrong we will fail during linking.  FIXME?
+	&& vfy_class_has_field_p (current_class, name))
+      // Note that we don't actually know whether we're going to match
+      // against 'this' or some other object of the same type.  So,
+      // here we set things up so that it doesn't matter.  This relies
+      // on knowing what our caller is up to.
+      class_type->set_uninitialized (type::EITHER, this);
+
+    return result;
   }
 
   type check_method_constant (int index, bool is_interface,
@@ -2768,15 +2820,8 @@
 	  case op_putfield:
 	    {
 	      type klass;
-	      type field = check_field_constant (get_ushort (), &klass);
+	      type field = check_field_constant (get_ushort (), &klass, true);
 	      pop_type (field);
-
-	      // We have an obscure special case here: we can use
-	      // 'putfield' on a field declared in this class, even if
-	      // 'this' has not yet been initialized.
-	      if (! current_state->this_type.isinitialized ()
-		  && current_state->this_type.pc == type::SELF)
-		klass.set_uninitialized (type::SELF, this);
 	      pop_type (klass);
 	    }
 	    break;


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