diff options
-rw-r--r-- | libjava/ChangeLog | 25 | ||||
-rw-r--r-- | libjava/defineclass.cc | 4 | ||||
-rw-r--r-- | libjava/verify.cc | 88 |
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); |