Commit f70443f7 by Per Bothner

verify.cc (verify_fail): Change from being a top-level function to e method of…

verify.cc (verify_fail): Change from being a top-level function to e method of _Jv_BytecodeVerifier.


	* verify.cc (verify_fail):  Change from being a top-level function
	to e method of _Jv_BytecodeVerifier.  Emit current method name.
	Pass the current verifier to type: and state: methods as needed,
	for better error messages, and for resolve.
	(resolve):  Pass current class's loader for Class.forName and
	_Jv_FindClassFromSignature, rather than using the default loader.
	(various type: and state: methods):  Take _Jv_BytecodeVerifier* arg.
	(get_type_val_for_signature):  Make non-static.
	(various methods):  Pass start_PC implicitly, not explicitly.

From-SVN: r49240
parent 63b3a44f
......@@ -39,11 +39,6 @@ details. */
// * at least one GC problem :-(
// This is global because __attribute__ doesn't seem to work on static
// methods.
static void verify_fail (char *msg, jint pc = -1)
__attribute__ ((__noreturn__));
static void debug_print (const char *fmt, ...)
__attribute__ ((format (printf, 1, 2)));
......@@ -180,7 +175,7 @@ private:
// Return the type_val corresponding to a primitive signature
// character. For instance `I' returns `int.class'.
static type_val get_type_val_for_signature (jchar sig)
type_val get_type_val_for_signature (jchar sig)
{
type_val rt;
switch (sig)
......@@ -219,7 +214,7 @@ private:
}
// Return the type_val corresponding to a primitive class.
static type_val get_type_val_for_signature (jclass k)
type_val get_type_val_for_signature (jclass k)
{
return get_type_val_for_signature ((jchar) k->method_count);
}
......@@ -390,35 +385,36 @@ private:
}
// If *THIS is an unresolved reference type, resolve it.
void resolve ()
void resolve (_Jv_BytecodeVerifier *verifier)
{
if (key != unresolved_reference_type
&& key != uninitialized_unresolved_reference_type)
return;
// FIXME: class loader
using namespace java::lang;
java::lang::ClassLoader *loader
= verifier->current_class->getClassLoader();
// We might see either kind of name. Sigh.
if (data.name->data[0] == 'L'
&& data.name->data[data.name->length - 1] == ';')
data.klass = _Jv_FindClassFromSignature (data.name->data, NULL);
data.klass = _Jv_FindClassFromSignature (data.name->data, loader);
else
data.klass = Class::forName (_Jv_NewStringUtf8Const (data.name),
false, NULL);
false, loader);
key = (key == unresolved_reference_type
? reference_type
: uninitialized_reference_type);
}
// Mark this type as the uninitialized result of `new'.
void set_uninitialized (int npc)
void set_uninitialized (int npc, _Jv_BytecodeVerifier *verifier)
{
if (key == reference_type)
key = uninitialized_reference_type;
else if (key == unresolved_reference_type)
key = uninitialized_unresolved_reference_type;
else
verify_fail ("internal error in type::uninitialized");
verifier->verify_fail ("internal error in type::uninitialized");
pc = npc;
}
......@@ -441,7 +437,7 @@ private:
// of type *THIS. Handle various special cases too. Might modify
// *THIS or K. Note however that this does not perform numeric
// promotion.
bool compatible (type &k)
bool compatible (type &k, _Jv_BytecodeVerifier *verifier)
{
// Any type is compatible with the unsuitable type.
if (key == unsuitable_type)
......@@ -482,8 +478,8 @@ private:
return true;
// We must resolve both types and check assignability.
resolve ();
k.resolve ();
resolve (verifier);
k.resolve (verifier);
return is_assignable_from_slow (data.klass, k.data.klass);
}
......@@ -515,17 +511,17 @@ private:
return false;
}
bool isinterface ()
bool isinterface (_Jv_BytecodeVerifier *verifier)
{
resolve ();
resolve (verifier);
if (key != reference_type)
return false;
return data.klass->isInterface ();
}
bool isabstract ()
bool isabstract (_Jv_BytecodeVerifier *verifier)
{
resolve ();
resolve (verifier);
if (key != reference_type)
return false;
using namespace java::lang::reflect;
......@@ -533,34 +529,34 @@ private:
}
// Return the element type of an array.
type element_type ()
type element_type (_Jv_BytecodeVerifier *verifier)
{
// FIXME: maybe should do string manipulation here.
resolve ();
resolve (verifier);
if (key != reference_type)
verify_fail ("programmer error in type::element_type()");
verifier->verify_fail ("programmer error in type::element_type()", -1);
jclass k = data.klass->getComponentType ();
if (k->isPrimitive ())
return type (get_type_val_for_signature (k));
return type (verifier->get_type_val_for_signature (k));
return type (k);
}
// Return the array type corresponding to an initialized
// reference. We could expand this to work for other kinds of
// types, but currently we don't need to.
type to_array ()
type to_array (_Jv_BytecodeVerifier *verifier)
{
// Resolving isn't ideal, because it might force us to load
// another class, but it's easy. FIXME?
if (key == unresolved_reference_type)
resolve ();
resolve (verifier);
if (key == reference_type)
return type (_Jv_GetArrayClass (data.klass,
data.klass->getClassLoader ()));
else
verify_fail ("internal error in type::to_array()");
verifier->verify_fail ("internal error in type::to_array()");
}
bool isreference () const
......@@ -587,7 +583,7 @@ private:
|| key == uninitialized_reference_type);
}
void verify_dimensions (int ndims)
void verify_dimensions (int ndims, _Jv_BytecodeVerifier *verifier)
{
// The way this is written, we don't need to check isarray().
if (key == reference_type)
......@@ -608,11 +604,11 @@ private:
}
if (ndims > 0)
verify_fail ("array type has fewer dimensions than required");
verifier->verify_fail ("array type has fewer dimensions than required");
}
// Merge OLD_TYPE into this. On error throw exception.
bool merge (type& old_type, bool local_semantics = false)
bool merge (type& old_type, bool local_semantics, _Jv_BytecodeVerifier *verifier)
{
bool changed = false;
bool refo = old_type.isreference ();
......@@ -627,7 +623,7 @@ private:
changed = true;
}
else if (isinitialized () != old_type.isinitialized ())
verify_fail ("merging initialized and uninitialized types");
verifier->verify_fail ("merging initialized and uninitialized types");
else
{
if (! isinitialized ())
......@@ -637,7 +633,7 @@ private:
else if (old_type.pc == UNINIT)
;
else if (pc != old_type.pc)
verify_fail ("merging different uninitialized types");
verifier->verify_fail ("merging different uninitialized types");
}
if (! isresolved ()
......@@ -648,8 +644,8 @@ private:
}
else
{
resolve ();
old_type.resolve ();
resolve (verifier);
old_type.resolve (verifier);
jclass k = data.klass;
jclass oldk = old_type.data.klass;
......@@ -708,7 +704,7 @@ private:
}
}
else
verify_fail ("unmergeable type");
verifier->verify_fail ("unmergeable type");
}
return changed;
}
......@@ -886,7 +882,7 @@ private:
// state. Returns true if the new state was in fact changed.
// Will throw an exception if the states are not mergeable.
bool merge (state *state_old, bool ret_semantics,
int max_locals)
int max_locals, _Jv_BytecodeVerifier *verifier)
{
bool changed = false;
......@@ -908,14 +904,14 @@ private:
changed = true;
}
else
verify_fail ("subroutines merged");
verifier->verify_fail ("subroutines merged");
// Merge stacks.
if (state_old->stacktop != stacktop)
verify_fail ("stack sizes differ");
verifier->verify_fail ("stack sizes differ");
for (int i = 0; i < state_old->stacktop; ++i)
{
if (stack[i].merge (state_old->stack[i]))
if (stack[i].merge (state_old->stack[i], false, verifier))
changed = true;
}
......@@ -924,7 +920,7 @@ private:
{
if (! ret_semantics || local_changed[i])
{
if (locals[i].merge (state_old->locals[i], true))
if (locals[i].merge (state_old->locals[i], true, verifier))
{
changed = true;
note_variable (i);
......@@ -945,27 +941,28 @@ private:
// whether we're using backwards-branch or exception-handing
// semantics.
void check_no_uninitialized_objects (int max_locals,
_Jv_BytecodeVerifier *verifier,
bool exception_semantics = false)
{
if (! exception_semantics)
{
for (int i = 0; i < stacktop; ++i)
if (stack[i].isreference () && ! stack[i].isinitialized ())
verify_fail ("uninitialized object on stack");
verifier->verify_fail ("uninitialized object on stack");
}
for (int i = 0; i < max_locals; ++i)
if (locals[i].isreference () && ! locals[i].isinitialized ())
verify_fail ("uninitialized object in local variable");
verifier->verify_fail ("uninitialized object in local variable");
check_this_initialized ();
check_this_initialized (verifier);
}
// Ensure that `this' has been initialized.
void check_this_initialized ()
void check_this_initialized (_Jv_BytecodeVerifier *verifier)
{
if (this_type.isreference () && ! this_type.isinitialized ())
verify_fail ("`this' is uninitialized");
verifier->verify_fail ("`this' is uninitialized");
}
// Set type of `this'.
......@@ -1028,7 +1025,7 @@ private:
type pop_raw ()
{
if (current_state->stacktop <= 0)
verify_fail ("stack empty", start_PC);
verify_fail ("stack empty");
type r = current_state->stack[--current_state->stacktop];
current_state->stackdepth -= r.depth ();
if (current_state->stackdepth < 0)
......@@ -1040,7 +1037,7 @@ private:
{
type r = pop_raw ();
if (r.iswide ())
verify_fail ("narrow pop of wide type", start_PC);
verify_fail ("narrow pop of wide type");
return r;
}
......@@ -1048,7 +1045,7 @@ private:
{
type r = pop_raw ();
if (! r.iswide ())
verify_fail ("wide pop of narrow type", start_PC);
verify_fail ("wide pop of narrow type");
return r;
}
......@@ -1056,8 +1053,8 @@ private:
{
match.promote ();
type t = pop_raw ();
if (! match.compatible (t))
verify_fail ("incompatible type on stack", start_PC);
if (! match.compatible (t, this))
verify_fail ("incompatible type on stack");
return t;
}
......@@ -1066,7 +1063,7 @@ private:
{
type t = pop_raw ();
if (! t.isreference () && t.key != return_address_type)
verify_fail ("expected reference or return address on stack", start_PC);
verify_fail ("expected reference or return address on stack");
return t;
}
......@@ -1109,14 +1106,14 @@ private:
{
int depth = t.depth ();
if (index > current_method->max_locals - depth)
verify_fail ("invalid local variable", start_PC);
if (! t.compatible (current_state->locals[index]))
verify_fail ("incompatible type in local variable", start_PC);
verify_fail ("invalid local variable");
if (! t.compatible (current_state->locals[index], this))
verify_fail ("incompatible type in local variable");
if (depth == 2)
{
type t (continuation_type);
if (! current_state->locals[index + 1].compatible (t))
verify_fail ("invalid local variable", start_PC);
if (! current_state->locals[index + 1].compatible (t, this))
verify_fail ("invalid local variable");
}
return current_state->locals[index];
}
......@@ -1128,8 +1125,8 @@ private:
if (! array.isarray ())
verify_fail ("array required");
type t = array.element_type ();
if (! element.compatible (t))
type t = array.element_type (this);
if (! element.compatible (t, this))
{
// Special case for byte arrays, which must also be boolean
// arrays.
......@@ -1137,7 +1134,7 @@ private:
if (element.key == byte_type)
{
type e2 (boolean_type);
ok = e2.compatible (t);
ok = e2.compatible (t, this);
}
if (! ok)
verify_fail ("incompatible array element type");
......@@ -1217,7 +1214,7 @@ private:
states[npc]->print (" To", npc, current_method->max_stack,
current_method->max_locals);
changed = states[npc]->merge (nstate, ret_semantics,
current_method->max_locals);
current_method->max_locals, this);
states[npc]->print ("New", npc, current_method->max_stack,
current_method->max_locals);
}
......@@ -1235,14 +1232,14 @@ private:
{
int npc = compute_jump (offset);
if (npc < PC)
current_state->check_no_uninitialized_objects (current_method->max_locals);
current_state->check_no_uninitialized_objects (current_method->max_locals, this);
push_jump_merge (npc, current_state);
}
void push_exception_jump (type t, int pc)
{
current_state->check_no_uninitialized_objects (current_method->max_locals,
true);
this, true);
state s (current_state, current_method->max_stack,
current_method->max_locals);
s.set_exception (t, current_method->max_stack);
......@@ -1336,7 +1333,7 @@ private:
// in the enclosing context.
current_state->subroutine = get_subroutine (subr->pc);
if (subr->pc < PC)
current_state->check_no_uninitialized_objects (current_method->max_locals);
current_state->check_no_uninitialized_objects (current_method->max_locals, this);
push_jump_merge (subr->pc, current_state, true);
}
......@@ -1361,7 +1358,7 @@ private:
int npc = compute_jump (offset);
if (npc < PC)
current_state->check_no_uninitialized_objects (current_method->max_locals);
current_state->check_no_uninitialized_objects (current_method->max_locals, this);
check_nonrecursive_call (current_state->subroutine, npc);
// Temporarily modify the current state so that it looks like we are
......@@ -1899,8 +1896,8 @@ private:
void check_return_type (type onstack)
{
type rt = compute_return_type (current_method->self->signature);
if (! rt.compatible (onstack))
verify_fail ("incompatible return type", start_PC);
if (! rt.compatible (onstack, this))
verify_fail ("incompatible return type");
}
// Initialize the stack for the new method. Returns true if this
......@@ -1916,7 +1913,7 @@ private:
type kurr (current_class);
if (_Jv_equalUtf8Consts (current_method->self->name, gcj::init_name))
{
kurr.set_uninitialized (type::SELF);
kurr.set_uninitialized (type::SELF, this);
is_init = true;
}
set_variable (0, kurr);
......@@ -1997,7 +1994,7 @@ private:
current_state->print ("Cur", PC, current_method->max_stack,
current_method->max_locals);
if (! current_state->merge (states[PC], false,
current_method->max_locals)
current_method->max_locals, this)
&& ! states[PC]->is_unmerged_ret_state (current_method->max_locals))
{
debug_print ("== Fall through optimization\n");
......@@ -2610,7 +2607,7 @@ private:
// We only need to check this when the return type is
// void, because all instance initializers return void.
if (this_is_init)
current_state->check_this_initialized ();
current_state->check_this_initialized (this);
check_return_type (void_type);
invalidate_pc ();
break;
......@@ -2639,7 +2636,7 @@ private:
// `this' has not yet been initialized.
if (! current_state->this_type.isinitialized ()
&& current_state->this_type.pc == type::SELF)
klass.set_uninitialized (type::SELF);
klass.set_uninitialized (type::SELF, this);
pop_type (klass);
}
break;
......@@ -2660,14 +2657,11 @@ private:
{
int nargs = get_byte ();
if (nargs == 0)
verify_fail ("too few arguments to invokeinterface",
start_PC);
verify_fail ("too few arguments to invokeinterface");
if (get_byte () != 0)
verify_fail ("invokeinterface dummy byte is wrong",
start_PC);
verify_fail ("invokeinterface dummy byte is wrong");
if (nargs - 1 != arg_count)
verify_fail ("wrong argument count for invokeinterface",
start_PC);
verify_fail ("wrong argument count for invokeinterface");
}
bool is_init = false;
......@@ -2675,11 +2669,10 @@ private:
{
is_init = true;
if (opcode != op_invokespecial)
verify_fail ("can't invoke <init>", start_PC);
verify_fail ("can't invoke <init>");
}
else if (method_name->data[0] == '<')
verify_fail ("can't invoke method starting with `<'",
start_PC);
verify_fail ("can't invoke method starting with `<'");
// Pop arguments and check types.
type arg_types[arg_count];
......@@ -2693,7 +2686,7 @@ private:
if (is_init)
{
// In this case the PC doesn't matter.
t.set_uninitialized (type::UNINIT);
t.set_uninitialized (type::UNINIT, this);
}
t = pop_type (t);
if (is_init)
......@@ -2710,10 +2703,9 @@ private:
case op_new:
{
type t = check_class_constant (get_ushort ());
if (t.isarray () || t.isinterface () || t.isabstract ())
verify_fail ("type is array, interface, or abstract",
start_PC);
t.set_uninitialized (start_PC);
if (t.isarray () || t.isinterface (this) || t.isabstract (this))
verify_fail ("type is array, interface, or abstract");
t.set_uninitialized (start_PC, this);
push_type (t);
}
break;
......@@ -2731,13 +2723,13 @@ private:
break;
case op_anewarray:
pop_type (int_type);
push_type (check_class_constant (get_ushort ()).to_array ());
push_type (check_class_constant (get_ushort ()).to_array (this));
break;
case op_arraylength:
{
type t = pop_type (reference_type);
if (! t.isarray ())
verify_fail ("array type expected", start_PC);
verify_fail ("array type expected");
push_type (int_type);
}
break;
......@@ -2812,7 +2804,7 @@ private:
int dim = get_byte ();
if (dim < 1)
verify_fail ("too few dimensions to multianewarray", start_PC);
atype.verify_dimensions (dim);
atype.verify_dimensions (dim, this);
for (int i = 0; i < dim; ++i)
pop_type (int_type);
push_type (atype);
......@@ -2839,6 +2831,34 @@ private:
}
}
__attribute__ ((__noreturn__)) void verify_fail (char *s, jint pc = -1)
{
using namespace java::lang;
StringBuffer *buf = new StringBuffer ();
buf->append (JvNewStringLatin1 ("verification failed"));
if (pc == -1)
pc = start_PC;
if (pc != -1)
{
buf->append (JvNewStringLatin1 (" at PC "));
buf->append (pc);
}
_Jv_InterpMethod *method = current_method;
buf->append (JvNewStringLatin1 (" in "));
buf->append (current_class->getName());
buf->append ((jchar) ':');
buf->append (JvNewStringUTF (method->get_method()->name->data));
buf->append ((jchar) '(');
buf->append (JvNewStringUTF (method->get_method()->signature->data));
buf->append ((jchar) ')');
buf->append (JvNewStringLatin1 (": "));
buf->append (JvNewStringLatin1 (s));
throw new java::lang::VerifyError (buf->toString ());
}
public:
void verify_instructions ()
......@@ -2889,23 +2909,4 @@ _Jv_VerifyMethod (_Jv_InterpMethod *meth)
_Jv_BytecodeVerifier v (meth);
v.verify_instructions ();
}
// FIXME: add more info, like PC, when required.
static void
verify_fail (char *s, jint pc)
{
using namespace java::lang;
StringBuffer *buf = new StringBuffer ();
buf->append (JvNewStringLatin1 ("verification failed"));
if (pc != -1)
{
buf->append (JvNewStringLatin1 (" at PC "));
buf->append (pc);
}
buf->append (JvNewStringLatin1 (": "));
buf->append (JvNewStringLatin1 (s));
throw new java::lang::VerifyError (buf->toString ());
}
#endif /* INTERPRETER */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment