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:
parent
20266bb121
commit
604407070b
2 changed files with 101 additions and 41 deletions
|
@ -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.
|
||||||
|
|
|
@ -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 = ¤t_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 = ¤t_class->constants;
|
_Jv_Constants *pool = ¤t_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);
|
||||||
¤t_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 */
|
||||||
|
|
Loading…
Add table
Reference in a new issue