verify.cc: Include StringBuffer.h.

* verify.cc: Include StringBuffer.h.
	(verify_fail): Added pc argument.  Use StringBuffer to construct
	exception message.
	(_Jv_BytecodeVerifier::verify_instructions_0): Put PC into error
	message.
	(_Jv_BytecodeVerifier::check_return_type): Likewise.
	(_Jv_BytecodeVerifier::handle_field_or_method): Likewise.
	(_Jv_BytecodeVerifier::check_constant): Likewise.
	(_Jv_BytecodeVerifier::check_class_constant): Likewise.
	(_Jv_BytecodeVerifier::check_pool_index): Likewise.
	(_Jv_BytecodeVerifier::get_variable): Likewise.
	(_Jv_BytecodeVerifier::branch_prepass): Likewise.  Also, correctly
	check exception handler endpoint.
	(_Jv_BytecodeVerifier::verify_instructions_0): Correctly handle
	wide arguments to current method.
	(_Jv_BytecodeVerifier::check_wide_constant): New method.
	(_Jv_BytecodeVerifier::verify_instructions_0) [op_ldc2_w]: Use
	it.

From-SVN: r47155
This commit is contained in:
Tom Tromey 2001-11-18 23:04:28 +00:00 committed by Tom Tromey
parent 20266bb121
commit 604407070b
2 changed files with 101 additions and 41 deletions

View file

@ -1,3 +1,24 @@
2001-11-18 Tom Tromey <tromey@redhat.com>
* verify.cc: Include StringBuffer.h.
(verify_fail): Added pc argument. Use StringBuffer to construct
exception message.
(_Jv_BytecodeVerifier::verify_instructions_0): Put PC into error
message.
(_Jv_BytecodeVerifier::check_return_type): Likewise.
(_Jv_BytecodeVerifier::handle_field_or_method): Likewise.
(_Jv_BytecodeVerifier::check_constant): Likewise.
(_Jv_BytecodeVerifier::check_class_constant): Likewise.
(_Jv_BytecodeVerifier::check_pool_index): Likewise.
(_Jv_BytecodeVerifier::get_variable): Likewise.
(_Jv_BytecodeVerifier::branch_prepass): Likewise. Also, correctly
check exception handler endpoint.
(_Jv_BytecodeVerifier::verify_instructions_0): Correctly handle
wide arguments to current method.
(_Jv_BytecodeVerifier::check_wide_constant): New method.
(_Jv_BytecodeVerifier::verify_instructions_0) [op_ldc2_w]: Use
it.
2001-11-17 Anthony Green <green@redhat.com> 2001-11-17 Anthony Green <green@redhat.com>
* jni.cc (unwrap): Fix test for wrapped objects. * jni.cc (unwrap): Fix test for wrapped objects.

View file

@ -23,6 +23,7 @@ details. */
#include <java/lang/VerifyError.h> #include <java/lang/VerifyError.h>
#include <java/lang/Throwable.h> #include <java/lang/Throwable.h>
#include <java/lang/reflect/Modifier.h> #include <java/lang/reflect/Modifier.h>
#include <java/lang/StringBuffer.h>
// TO DO // TO DO
@ -36,7 +37,8 @@ details. */
// This is global because __attribute__ doesn't seem to work on static // This is global because __attribute__ doesn't seem to work on static
// methods. // methods.
static void verify_fail (char *s) __attribute__ ((__noreturn__)); static void verify_fail (char *msg, jint pc = -1)
__attribute__ ((__noreturn__));
class _Jv_BytecodeVerifier class _Jv_BytecodeVerifier
{ {
@ -903,14 +905,14 @@ private:
{ {
int depth = t.depth (); int depth = t.depth ();
if (index > current_method->max_locals - depth) if (index > current_method->max_locals - depth)
verify_fail ("invalid local variable"); verify_fail ("invalid local variable", start_PC);
if (! t.compatible (current_state->locals[index])) if (! t.compatible (current_state->locals[index]))
verify_fail ("incompatible type in local variable"); verify_fail ("incompatible type in local variable", start_PC);
if (depth == 2) if (depth == 2)
{ {
type t (continuation_type); type t (continuation_type);
if (! current_state->locals[index + 1].compatible (t)) if (! current_state->locals[index + 1].compatible (t))
verify_fail ("invalid local variable"); verify_fail ("invalid local variable", start_PC);
} }
current_state->note_variable (index); current_state->note_variable (index);
return current_state->locals[index]; return current_state->locals[index];
@ -1407,7 +1409,7 @@ private:
jint low = get_int (); jint low = get_int ();
jint hi = get_int (); jint hi = get_int ();
if (low > hi) if (low > hi)
verify_fail ("invalid tableswitch"); verify_fail ("invalid tableswitch", start_PC);
for (int i = low; i <= hi; ++i) for (int i = low; i <= hi; ++i)
note_branch_target (compute_jump (get_int ())); note_branch_target (compute_jump (get_int ()));
} }
@ -1419,7 +1421,7 @@ private:
note_branch_target (compute_jump (get_int ())); note_branch_target (compute_jump (get_int ()));
int npairs = get_int (); int npairs = get_int ();
if (npairs < 0) if (npairs < 0)
verify_fail ("too few pairs in lookupswitch"); verify_fail ("too few pairs in lookupswitch", start_PC);
while (npairs-- > 0) while (npairs-- > 0)
{ {
get_int (); get_int ();
@ -1451,7 +1453,8 @@ private:
break; break;
default: default:
verify_fail ("unrecognized instruction in branch_prepass"); verify_fail ("unrecognized instruction in branch_prepass",
start_PC);
} }
// See if any previous branch tried to branch to the middle of // See if any previous branch tried to branch to the middle of
@ -1459,7 +1462,7 @@ private:
for (int pc = start_PC + 1; pc < PC; ++pc) for (int pc = start_PC + 1; pc < PC; ++pc)
{ {
if ((flags[pc] & FLAG_BRANCH_TARGET)) if ((flags[pc] & FLAG_BRANCH_TARGET))
verify_fail ("branch not to instruction start"); verify_fail ("branch to middle of instruction", pc);
} }
} }
@ -1467,12 +1470,16 @@ private:
for (int i = 0; i < current_method->exc_count; ++i) for (int i = 0; i < current_method->exc_count; ++i)
{ {
if (! (flags[exception[i].handler_pc] & FLAG_INSN_START)) if (! (flags[exception[i].handler_pc] & FLAG_INSN_START))
verify_fail ("exception handler not at instruction start"); verify_fail ("exception handler not at instruction start",
exception[i].handler_pc);
if (exception[i].start_pc > exception[i].end_pc) if (exception[i].start_pc > exception[i].end_pc)
verify_fail ("exception range inverted"); verify_fail ("exception range inverted");
if (! (flags[exception[i].start_pc] & FLAG_INSN_START) if (! (flags[exception[i].start_pc] & FLAG_INSN_START))
|| ! (flags[exception[i].start_pc] & FLAG_INSN_START)) verify_fail ("exception start not at instruction start",
verify_fail ("exception endpoint not at instruction start"); exception[i].start_pc);
else if (! (flags[exception[i].end_pc] & FLAG_INSN_START))
verify_fail ("exception end not at instruction start",
exception[i].end_pc);
flags[exception[i].handler_pc] |= FLAG_BRANCH_TARGET; flags[exception[i].handler_pc] |= FLAG_BRANCH_TARGET;
} }
@ -1481,7 +1488,7 @@ private:
void check_pool_index (int index) void check_pool_index (int index)
{ {
if (index < 0 || index >= current_class->constants.size) if (index < 0 || index >= current_class->constants.size)
verify_fail ("constant pool index out of range"); verify_fail ("constant pool index out of range", start_PC);
} }
type check_class_constant (int index) type check_class_constant (int index)
@ -1492,7 +1499,7 @@ private:
return type (pool->data[index].clazz); return type (pool->data[index].clazz);
else if (pool->tags[index] == JV_CONSTANT_Class) else if (pool->tags[index] == JV_CONSTANT_Class)
return type (pool->data[index].utf8); return type (pool->data[index].utf8);
verify_fail ("expected class constant"); verify_fail ("expected class constant", start_PC);
} }
type check_constant (int index) type check_constant (int index)
@ -1506,7 +1513,18 @@ private:
return type (int_type); return type (int_type);
else if (pool->tags[index] == JV_CONSTANT_Float) else if (pool->tags[index] == JV_CONSTANT_Float)
return type (float_type); return type (float_type);
verify_fail ("String, int, or float constant expected"); verify_fail ("String, int, or float constant expected", start_PC);
}
type check_wide_constant (int index)
{
check_pool_index (index);
_Jv_Constants *pool = &current_class->constants;
if (pool->tags[index] == JV_CONSTANT_Long)
return type (long_type);
else if (pool->tags[index] == JV_CONSTANT_Double)
return type (double_type);
verify_fail ("long or double constant expected", start_PC);
} }
// Helper for both field and method. These are laid out the same in // Helper for both field and method. These are laid out the same in
@ -1518,7 +1536,7 @@ private:
check_pool_index (index); check_pool_index (index);
_Jv_Constants *pool = &current_class->constants; _Jv_Constants *pool = &current_class->constants;
if (pool->tags[index] != expected) if (pool->tags[index] != expected)
verify_fail ("didn't see expected constant"); verify_fail ("didn't see expected constant", start_PC);
// Once we know we have a Fieldref or Methodref we assume that it // Once we know we have a Fieldref or Methodref we assume that it
// is correctly laid out in the constant pool. I think the code // is correctly laid out in the constant pool. I think the code
// in defineclass.cc guarantees this. // in defineclass.cc guarantees this.
@ -1626,7 +1644,7 @@ private:
{ {
type rt = compute_return_type (current_method->self->signature); type rt = compute_return_type (current_method->self->signature);
if (! expected.compatible (rt)) if (! expected.compatible (rt))
verify_fail ("incompatible return type"); verify_fail ("incompatible return type", start_PC);
} }
void verify_instructions_0 () void verify_instructions_0 ()
@ -1635,6 +1653,7 @@ private:
current_method->max_locals); current_method->max_locals);
PC = 0; PC = 0;
start_PC = 0;
{ {
int var = 0; int var = 0;
@ -1649,11 +1668,17 @@ private:
++var; ++var;
} }
if (var + _Jv_count_arguments (current_method->self->signature) // We have to handle wide arguments specially here.
> current_method->max_locals) int arg_count = _Jv_count_arguments (current_method->self->signature);
verify_fail ("too many arguments"); type arg_types[arg_count];
compute_argument_types (current_method->self->signature, compute_argument_types (current_method->self->signature, arg_types);
&current_state->locals[var]); for (int i = 0; i < arg_count; ++i)
{
set_variable (var, arg_types[i]);
++var;
if (arg_types[i].iswide ())
++var;
}
} }
states = (state **) _Jv_Malloc (sizeof (state *) states = (state **) _Jv_Malloc (sizeof (state *)
@ -1670,7 +1695,7 @@ private:
{ {
PC = pop_jump (); PC = pop_jump ();
if (PC == state::INVALID) if (PC == state::INVALID)
verify_fail ("saw state::INVALID"); verify_fail ("saw state::INVALID", start_PC);
if (PC == state::NO_NEXT) if (PC == state::NO_NEXT)
break; break;
// Set up the current state. // Set up the current state.
@ -1771,7 +1796,7 @@ private:
push_type (check_constant (get_ushort ())); push_type (check_constant (get_ushort ()));
break; break;
case op_ldc2_w: case op_ldc2_w:
push_type (check_constant (get_ushort ())); push_type (check_wide_constant (get_ushort ()));
break; break;
case op_iload: case op_iload:
@ -2253,7 +2278,7 @@ private:
{ {
jint key = get_int (); jint key = get_int ();
if (i > 0 && key <= lastkey) if (i > 0 && key <= lastkey)
verify_fail ("lookupswitch pairs unsorted"); verify_fail ("lookupswitch pairs unsorted", start_PC);
lastkey = key; lastkey = key;
push_jump (get_int ()); push_jump (get_int ());
} }
@ -2323,11 +2348,14 @@ private:
{ {
int nargs = get_byte (); int nargs = get_byte ();
if (nargs == 0) if (nargs == 0)
verify_fail ("too few arguments to invokeinterface"); verify_fail ("too few arguments to invokeinterface",
start_PC);
if (get_byte () != 0) if (get_byte () != 0)
verify_fail ("invokeinterface dummy byte is wrong"); verify_fail ("invokeinterface dummy byte is wrong",
start_PC);
if (nargs - 1 != arg_count) if (nargs - 1 != arg_count)
verify_fail ("wrong argument count for invokeinterface"); verify_fail ("wrong argument count for invokeinterface",
start_PC);
} }
bool is_init = false; bool is_init = false;
@ -2335,10 +2363,11 @@ private:
{ {
is_init = true; is_init = true;
if (opcode != (unsigned char) op_invokespecial) if (opcode != (unsigned char) op_invokespecial)
verify_fail ("can't invoke <init>"); verify_fail ("can't invoke <init>", start_PC);
} }
else if (method_name->data[0] == '<') else if (method_name->data[0] == '<')
verify_fail ("can't invoke method starting with `<'"); verify_fail ("can't invoke method starting with `<'",
start_PC);
// Pop arguments and check types. // Pop arguments and check types.
type arg_types[arg_count]; type arg_types[arg_count];
@ -2370,7 +2399,8 @@ private:
{ {
type t = check_class_constant (get_ushort ()); type t = check_class_constant (get_ushort ());
if (t.isarray () || t.isinterface () || t.isabstract ()) if (t.isarray () || t.isinterface () || t.isabstract ())
verify_fail ("type is array, interface, or abstract"); verify_fail ("type is array, interface, or abstract",
start_PC);
t.set_uninitialized (start_PC); t.set_uninitialized (start_PC);
push_type (t); push_type (t);
} }
@ -2382,7 +2412,7 @@ private:
// We intentionally have chosen constants to make this // We intentionally have chosen constants to make this
// valid. // valid.
if (atype < boolean_type || atype > long_type) if (atype < boolean_type || atype > long_type)
verify_fail ("type not primitive"); verify_fail ("type not primitive", start_PC);
pop_type (int_type); pop_type (int_type);
push_type (construct_primitive_array_type (type_val (atype))); push_type (construct_primitive_array_type (type_val (atype)));
} }
@ -2395,7 +2425,7 @@ private:
{ {
type t = pop_type (reference_type); type t = pop_type (reference_type);
if (! t.isarray ()) if (! t.isarray ())
verify_fail ("array type expected"); verify_fail ("array type expected", start_PC);
push_type (int_type); push_type (int_type);
} }
break; break;
@ -2460,7 +2490,7 @@ private:
get_short (); get_short ();
break; break;
default: default:
verify_fail ("unrecognized wide instruction"); verify_fail ("unrecognized wide instruction", start_PC);
} }
} }
break; break;
@ -2469,7 +2499,7 @@ private:
type atype = check_class_constant (get_ushort ()); type atype = check_class_constant (get_ushort ());
int dim = get_byte (); int dim = get_byte ();
if (dim < 1) if (dim < 1)
verify_fail ("too few dimensions to multianewarray"); verify_fail ("too few dimensions to multianewarray", start_PC);
atype.verify_dimensions (dim); atype.verify_dimensions (dim);
for (int i = 0; i < dim; ++i) for (int i = 0; i < dim; ++i)
pop_type (int_type); pop_type (int_type);
@ -2491,7 +2521,8 @@ private:
default: default:
// Unrecognized opcode. // Unrecognized opcode.
verify_fail ("unrecognized instruction in verify_instructions_0"); verify_fail ("unrecognized instruction in verify_instructions_0",
start_PC);
} }
} }
} }
@ -2536,12 +2567,20 @@ _Jv_VerifyMethod (_Jv_InterpMethod *meth)
// FIXME: add more info, like PC, when required. // FIXME: add more info, like PC, when required.
static void static void
verify_fail (char *s) verify_fail (char *s, jint pc)
{ {
char buf[1024]; using namespace java::lang;
strcpy (buf, "verification failed: "); StringBuffer *buf = new StringBuffer ();
strcat (buf, s);
throw new java::lang::VerifyError (JvNewStringLatin1 (buf)); 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 */ #endif /* INTERPRETER */