This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
[gcjx] Patch: FYI: verifier bug fix
- From: Tom Tromey <tromey at redhat dot com>
- To: Java Patch List <java-patches at gcc dot gnu dot org>
- Date: 26 Mar 2005 19:34:37 -0700
- Subject: [gcjx] Patch: FYI: verifier bug fix
- Reply-to: tromey at redhat dot com
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;