Commit ef9f3bc4 by Tom Tromey Committed by Tom Tromey

defineclass.cc (read_one_method_attribute): `end_pc' for an exception can be equal to code length.

	* defineclass.cc (read_one_method_attribute): `end_pc' for an
	exception can be equal to code length.
	* verify.cc (_Jv_BytecodeVerifier::verify_instructions_0): Removed
	`start_PC' from error invocation where it didn't make sense, and
	updated error message.  Use `copy' to copy a state.  Only try to
	merge current state with saved state when we've fallen through
	from the previous instruction.
	(_Jv_BytecodeVerifier::pop_ref_or_return): New method.
	(_Jv_BytecodeVerifier::verify_instructions_0) [op_astore_0]: Use
	pop_ref_or_return.
	(_Jv_BytecodeVerifier::verify_instructions_0) [op_astore]:
	Likewise.
	(_Jv_BytecodeVerifier::push_jump_merge): Pass max_locals, not
	max_stack, to merge.
	(_Jv_BytecodeVerifier::verify_instructions_0): Likewise.
	(_Jv_BytecodeVerifier::push_jump_merge): Merge from new state into
	state at branch target, not vice versa.
	(_Jv_BytecodeVerifier::branch_prepass): Allow end of exception to
	be equal to code length.  Removed redundant test to see if
	exception start is after exception end.
	(_Jv_BytecodeVerifier::verify_instructions_0): Type of argument to
	`finally' is Throwable.

From-SVN: r47623
parent 5b5e609d
2001-12-04 Tom Tromey <tromey@redhat.com>
* defineclass.cc (read_one_method_attribute): `end_pc' for an
exception can be equal to code length.
* verify.cc (_Jv_BytecodeVerifier::verify_instructions_0): Removed
`start_PC' from error invocation where it didn't make sense, and
updated error message. Use `copy' to copy a state. Only try to
merge current state with saved state when we've fallen through
from the previous instruction.
(_Jv_BytecodeVerifier::pop_ref_or_return): New method.
(_Jv_BytecodeVerifier::verify_instructions_0) [op_astore_0]: Use
pop_ref_or_return.
(_Jv_BytecodeVerifier::verify_instructions_0) [op_astore]:
Likewise.
(_Jv_BytecodeVerifier::push_jump_merge): Pass max_locals, not
max_stack, to merge.
(_Jv_BytecodeVerifier::verify_instructions_0): Likewise.
(_Jv_BytecodeVerifier::push_jump_merge): Merge from new state into
state at branch target, not vice versa.
(_Jv_BytecodeVerifier::branch_prepass): Allow end of exception to
be equal to code length. Removed redundant test to see if
exception start is after exception end.
(_Jv_BytecodeVerifier::verify_instructions_0): Type of argument to
`finally' is Throwable.
2001-12-04 Bryce McKinlay <bryce@waitaki.otago.ac.nz> 2001-12-04 Bryce McKinlay <bryce@waitaki.otago.ac.nz>
* Makefile.in: Rebuilt with automake-gcj. * Makefile.in: Rebuilt with automake-gcj.
......
...@@ -582,7 +582,9 @@ void _Jv_ClassReader::read_one_method_attribute (int method_index) ...@@ -582,7 +582,9 @@ void _Jv_ClassReader::read_one_method_attribute (int method_index)
if (start_pc > end_pc if (start_pc > end_pc
|| start_pc < 0 || start_pc < 0
|| end_pc >= code_length // END_PC can be equal to CODE_LENGTH.
// See JVM Spec 4.7.4.
|| end_pc > code_length
|| handler_pc >= code_length) || handler_pc >= code_length)
throw_class_format_error ("erroneous exception handler info"); throw_class_format_error ("erroneous exception handler info");
......
...@@ -8,7 +8,7 @@ This software is copyrighted work licensed under the terms of the ...@@ -8,7 +8,7 @@ This software is copyrighted work licensed under the terms of the
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
details. */ details. */
// Writte by Tom Tromey <tromey@redhat.com> // Written by Tom Tromey <tromey@redhat.com>
#include <config.h> #include <config.h>
...@@ -889,6 +889,15 @@ private: ...@@ -889,6 +889,15 @@ private:
return t; return t;
} }
// Pop a reference type or a return address.
type pop_ref_or_return ()
{
type t = pop_raw ();
if (! t.isreference () && t.key != return_address_type)
verify_fail ("expected reference or return address on stack", start_PC);
return t;
}
void push_type (type t) void push_type (type t)
{ {
// If T is a numeric type like short, promote it to int. // If T is a numeric type like short, promote it to int.
...@@ -1006,10 +1015,11 @@ private: ...@@ -1006,10 +1015,11 @@ private:
return npc; return npc;
} }
// Merge the indicated state into a new state and schedule a new PC if // Merge the indicated state into the state at the branch target and
// there is a change. If RET_SEMANTICS is true, then we are merging // schedule a new PC if there is a change. If RET_SEMANTICS is
// from a `ret' instruction into the instruction after a `jsr'. This // true, then we are merging from a `ret' instruction into the
// is a special case with its own modified semantics. // instruction after a `jsr'. This is a special case with its own
// modified semantics.
void push_jump_merge (int npc, state *nstate, bool ret_semantics = false) void push_jump_merge (int npc, state *nstate, bool ret_semantics = false)
{ {
bool changed = true; bool changed = true;
...@@ -1021,8 +1031,8 @@ private: ...@@ -1021,8 +1031,8 @@ private:
current_method->max_locals); current_method->max_locals);
} }
else else
changed = nstate->merge (states[npc], ret_semantics, changed = states[npc]->merge (nstate, ret_semantics,
current_method->max_stack); current_method->max_locals);
if (changed && states[npc]->next == state::INVALID) if (changed && states[npc]->next == state::INVALID)
{ {
...@@ -1506,12 +1516,11 @@ private: ...@@ -1506,12 +1516,11 @@ private:
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); exception[i].handler_pc);
if (exception[i].start_pc > exception[i].end_pc)
verify_fail ("exception range inverted");
if (! (flags[exception[i].start_pc] & FLAG_INSN_START)) if (! (flags[exception[i].start_pc] & FLAG_INSN_START))
verify_fail ("exception start not at instruction start", verify_fail ("exception start not at instruction start",
exception[i].start_pc); exception[i].start_pc);
else if (! (flags[exception[i].end_pc] & FLAG_INSN_START)) if (exception[i].end_pc != current_method->code_length
&& ! (flags[exception[i].end_pc] & FLAG_INSN_START))
verify_fail ("exception end not at instruction start", verify_fail ("exception end not at instruction start",
exception[i].end_pc); exception[i].end_pc);
...@@ -1729,24 +1738,33 @@ private: ...@@ -1729,24 +1738,33 @@ private:
{ {
PC = pop_jump (); PC = pop_jump ();
if (PC == state::INVALID) if (PC == state::INVALID)
verify_fail ("saw state::INVALID", start_PC); verify_fail ("can't happen: saw state::INVALID");
if (PC == state::NO_NEXT) if (PC == state::NO_NEXT)
break; break;
// Set up the current state. // Set up the current state.
*current_state = *states[PC]; current_state->copy (states[PC], current_method->max_stack,
current_method->max_locals);
} }
else
// Control can't fall off the end of the bytecode. {
// Control can't fall off the end of the bytecode. We
// only need to check this in the fall-through case,
// because branch bounds are checked when they are
// pushed.
if (PC >= current_method->code_length) if (PC >= current_method->code_length)
verify_fail ("fell off end"); verify_fail ("fell off end");
// We only have to do this checking in the situation where
// control flow falls through from the previous
// instruction. Otherwise merging is done at the time we
// push the branch.
if (states[PC] != NULL) if (states[PC] != NULL)
{ {
// We've already visited this instruction. So merge the // We've already visited this instruction. So merge
// states together. If this yields no change then we don't // the states together. If this yields no change then
// have to re-verify. // we don't have to re-verify.
if (! current_state->merge (states[PC], false, if (! current_state->merge (states[PC], false,
current_method->max_stack)) current_method->max_locals))
{ {
invalidate_pc (); invalidate_pc ();
continue; continue;
...@@ -1755,9 +1773,13 @@ private: ...@@ -1755,9 +1773,13 @@ private:
states[PC]->copy (current_state, current_method->max_stack, states[PC]->copy (current_state, current_method->max_stack,
current_method->max_locals); current_method->max_locals);
} }
else if ((flags[PC] & FLAG_BRANCH_TARGET)) }
// We only have to keep saved state at branch targets. If
// we're at a branch target and the state here hasn't been set
// yet, we set it now.
if (states[PC] == NULL && (flags[PC] & FLAG_BRANCH_TARGET))
{ {
// We only have to keep saved state at branch targets.
states[PC] = new state (current_state, current_method->max_stack, states[PC] = new state (current_state, current_method->max_stack,
current_method->max_locals); current_method->max_locals);
} }
...@@ -1769,7 +1791,7 @@ private: ...@@ -1769,7 +1791,7 @@ private:
{ {
if (PC >= exception[i].start_pc && PC < exception[i].end_pc) if (PC >= exception[i].start_pc && PC < exception[i].end_pc)
{ {
type handler = reference_type; type handler (&java::lang::Throwable::class$);
if (exception[i].handler_type != 0) if (exception[i].handler_type != 0)
handler = check_class_constant (exception[i].handler_type); handler = check_class_constant (exception[i].handler_type);
push_exception_jump (handler, exception[i].handler_pc); push_exception_jump (handler, exception[i].handler_pc);
...@@ -1932,7 +1954,7 @@ private: ...@@ -1932,7 +1954,7 @@ private:
set_variable (get_byte (), pop_type (double_type)); set_variable (get_byte (), pop_type (double_type));
break; break;
case op_astore: case op_astore:
set_variable (get_byte (), pop_type (reference_type)); set_variable (get_byte (), pop_ref_or_return ());
break; break;
case op_istore_0: case op_istore_0:
case op_istore_1: case op_istore_1:
...@@ -1962,7 +1984,7 @@ private: ...@@ -1962,7 +1984,7 @@ private:
case op_astore_1: case op_astore_1:
case op_astore_2: case op_astore_2:
case op_astore_3: case op_astore_3:
set_variable (opcode - op_astore_0, pop_type (reference_type)); set_variable (opcode - op_astore_0, pop_ref_or_return ());
break; break;
case op_iastore: case op_iastore:
pop_type (int_type); pop_type (int_type);
......
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