aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libjava/ChangeLog25
-rw-r--r--libjava/defineclass.cc4
-rw-r--r--libjava/verify.cc88
3 files changed, 83 insertions, 34 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index 8865548e..1e1311a 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,28 @@
+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>
* Makefile.in: Rebuilt with automake-gcj.
diff --git a/libjava/defineclass.cc b/libjava/defineclass.cc
index 31a4662..5fb8de3 100644
--- a/libjava/defineclass.cc
+++ b/libjava/defineclass.cc
@@ -582,7 +582,9 @@ void _Jv_ClassReader::read_one_method_attribute (int method_index)
if (start_pc > end_pc
|| 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)
throw_class_format_error ("erroneous exception handler info");
diff --git a/libjava/verify.cc b/libjava/verify.cc
index d4017eb..3016ea4 100644
--- a/libjava/verify.cc
+++ b/libjava/verify.cc
@@ -8,7 +8,7 @@ This software is copyrighted work licensed under the terms of the
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
details. */
-// Writte by Tom Tromey <tromey@redhat.com>
+// Written by Tom Tromey <tromey@redhat.com>
#include <config.h>
@@ -889,6 +889,15 @@ private:
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)
{
// If T is a numeric type like short, promote it to int.
@@ -1006,10 +1015,11 @@ private:
return npc;
}
- // Merge the indicated state into a new state and schedule a new PC if
- // there is a change. If RET_SEMANTICS is true, then we are merging
- // from a `ret' instruction into the instruction after a `jsr'. This
- // is a special case with its own modified semantics.
+ // Merge the indicated state into the state at the branch target and
+ // schedule a new PC if there is a change. If RET_SEMANTICS is
+ // true, then we are merging from a `ret' instruction into the
+ // 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)
{
bool changed = true;
@@ -1021,8 +1031,8 @@ private:
current_method->max_locals);
}
else
- changed = nstate->merge (states[npc], ret_semantics,
- current_method->max_stack);
+ changed = states[npc]->merge (nstate, ret_semantics,
+ current_method->max_locals);
if (changed && states[npc]->next == state::INVALID)
{
@@ -1506,12 +1516,11 @@ private:
if (! (flags[exception[i].handler_pc] & FLAG_INSN_START))
verify_fail ("exception handler not at instruction start",
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))
verify_fail ("exception start not at instruction start",
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",
exception[i].end_pc);
@@ -1729,35 +1738,48 @@ private:
{
PC = pop_jump ();
if (PC == state::INVALID)
- verify_fail ("saw state::INVALID", start_PC);
+ verify_fail ("can't happen: saw state::INVALID");
if (PC == state::NO_NEXT)
break;
// Set up the current state.
- *current_state = *states[PC];
+ current_state->copy (states[PC], current_method->max_stack,
+ current_method->max_locals);
}
-
- // Control can't fall off the end of the bytecode.
- if (PC >= current_method->code_length)
- verify_fail ("fell off end");
-
- if (states[PC] != NULL)
+ else
{
- // We've already visited this instruction. So merge the
- // states together. If this yields no change then we don't
- // have to re-verify.
- if (! current_state->merge (states[PC], false,
- current_method->max_stack))
+ // 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)
+ 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)
{
- invalidate_pc ();
- continue;
+ // We've already visited this instruction. So merge
+ // the states together. If this yields no change then
+ // we don't have to re-verify.
+ if (! current_state->merge (states[PC], false,
+ current_method->max_locals))
+ {
+ invalidate_pc ();
+ continue;
+ }
+ // Save a copy of it for later.
+ states[PC]->copy (current_state, current_method->max_stack,
+ current_method->max_locals);
}
- // Save a copy of it for later.
- states[PC]->copy (current_state, current_method->max_stack,
- 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,
current_method->max_locals);
}
@@ -1769,7 +1791,7 @@ private:
{
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)
handler = check_class_constant (exception[i].handler_type);
push_exception_jump (handler, exception[i].handler_pc);
@@ -1932,7 +1954,7 @@ private:
set_variable (get_byte (), pop_type (double_type));
break;
case op_astore:
- set_variable (get_byte (), pop_type (reference_type));
+ set_variable (get_byte (), pop_ref_or_return ());
break;
case op_istore_0:
case op_istore_1:
@@ -1962,7 +1984,7 @@ private:
case op_astore_1:
case op_astore_2:
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;
case op_iastore:
pop_type (int_type);