This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Java bytecode verifier patch
- To: egcs-patches at egcs dot cygnus dot com
- Subject: Java bytecode verifier patch
- From: Andrew Haley <aph at pasanda dot cygnus dot co dot uk>
- Date: 21 Jun 1999 16:18:45 -0000
This patch fixes a couple of bugs in the Java bytecode verifier which
cause programs to be incorrectly rejected.
Andrew.
1999-06-21 Andrew Haley <aph@cygnus.com>
* except.c (find_handler_in_range): The upper limit for exception
ranges is exclusive, not inclusive: (start <= pc < end).
(link_handler): find child pointer which points to outer by
searching sibling list: previous code incorrectly assumed that
outer->outer->first_child must point to outer.
* verify.c (verify_jvm_instructions): FIXME added to code for
`athrow'.
(verify_jvm_instructions): Do not assume that the last block
processed in a subroutine is a block which ends with a `ret'
instruction. With some control flows it is possible that the last
block ends with an `athrow'.
Index: gcc/java/verify.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/java/verify.c,v
retrieving revision 1.18
diff -c -2 -p -r1.18 verify.c
*** gcc/java/verify.c 1999/05/19 11:30:21 1.18
--- gcc/java/verify.c 1999/06/21 16:14:46
*************** verify_jvm_instructions (jcf, byte_ops,
*** 1000,1003 ****
--- 1000,1004 ----
case OPCODE_athrow:
+ // FIXME: athrow also empties the stack.
pop_type (throwable_type_node);
INVALIDATE_PC;
*************** verify_jvm_instructions (jcf, byte_ops,
*** 1198,1201 ****
--- 1199,1212 ----
}
+
+ }
+ break;
+ case OPCODE_jsr_w:
+ case OPCODE_ret_w:
+ default:
+ error ("unknown opcode %d@pc=%d during verification", op_code, PC-1);
+ return 0;
+ }
+
/* Check if there are any more pending blocks in this subroutine.
Because we push pending blocks in a last-in-first-out order,
*************** verify_jvm_instructions (jcf, byte_ops,
*** 1204,1216 ****
then we are done if the top of the pending_blocks stack is
not in a subroutine, or it is in our caller. */
if (pending_blocks == NULL_TREE
|| ! LABEL_IN_SUBR (pending_blocks)
|| LABEL_SUBR_START (pending_blocks) == caller)
{
! /* Since we are done with this subroutine (i.e. this is the
! last ret from it), set up the (so far known) return
! address as pending - with the merged type state. */
! tmp = LABEL_RETURN_LABELS (current_subr);
! current_subr = caller;
for ( ; tmp != NULL_TREE; tmp = TREE_CHAIN (tmp))
{
--- 1215,1242 ----
then we are done if the top of the pending_blocks stack is
not in a subroutine, or it is in our caller. */
+ if (current_subr
+ && PC == INVALID_PC)
+ {
+ tree caller = LABEL_SUBR_CONTEXT (current_subr);
+
if (pending_blocks == NULL_TREE
|| ! LABEL_IN_SUBR (pending_blocks)
|| LABEL_SUBR_START (pending_blocks) == caller)
+ {
+ int size = DECL_MAX_LOCALS(current_function_decl)+stack_pointer;
+ tree ret_map = LABEL_RETURN_TYPE_STATE (current_subr);
+ tmp = LABEL_RETURN_LABELS (current_subr);
+
+ /* FIXME: If we exit a subroutine via a throw, we might
+ have returned to an earlier caller. Obviously a
+ "ret" can only return one level, but a throw may
+ return many levels.*/
+ current_subr = caller;
+
+ if (RETURN_MAP_ADJUSTED (ret_map))
{
! /* Since we are done with this subroutine , set up
! the (so far known) return address as pending -
! with the merged type state. */
for ( ; tmp != NULL_TREE; tmp = TREE_CHAIN (tmp))
{
*************** verify_jvm_instructions (jcf, byte_ops,
*** 1242,1251 ****
}
}
- break;
- case OPCODE_jsr_w:
- case OPCODE_ret_w:
- default:
- error ("unknown opcode %d@pc=%d during verification", op_code, PC-1);
- return 0;
}
--- 1268,1271 ----
Index: gcc/java/except.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/java/except.c,v
retrieving revision 1.10
diff -c -2 -p -r1.10 except.c
*** gcc/java/except.c 1999/06/02 11:00:43 1.10
--- gcc/java/except.c 1999/06/21 16:14:46
*************** find_handler_in_range (pc, range, child)
*** 73,77 ****
if (pc < child->start_pc)
break;
! if (pc <= child->end_pc)
return find_handler_in_range (pc, child, child->first_child);
}
--- 73,77 ----
if (pc < child->start_pc)
break;
! if (pc < child->end_pc)
return find_handler_in_range (pc, child, child->first_child);
}
*************** link_handler (range, outer)
*** 130,134 ****
range->next_sibling = NULL;
range->first_child = outer;
! outer->outer->first_child = range;
outer->outer = range;
return;
--- 130,139 ----
range->next_sibling = NULL;
range->first_child = outer;
! {
! struct eh_range **pr = &(outer->outer->first_child);
! while (*pr != outer)
! pr = &(*pr)->next_sibling;
! *pr = range;
! }
outer->outer = range;
return;