Commit 984ad2c6 by Per Bothner Committed by Per Bothner

Various patches to emit better messages on verification errors.

From-SVN: r39019
parent 150d3c00
2001-01-14 Per Bothner <per@bothner.com> 2001-01-14 Per Bothner <per@bothner.com>
Various patches to emit better messages on verification errors.
* expr.c (push_type_0): Return error indication on stack overflow,
instead of callinfg fatal.
(push_type): Now just call push_type_0 (nd fatal on overflow).
(pop_type_0): Return detailed error message (in a char** argument).
(pop_type): If pop_type_0 fails, print error message.
(pop_argument_types): Moved to verify.c.
* verify.c (pop_argument_types): Moved from expr.c.
Return a (possible) error message, rather than void.
(POP_TYPE, POP_TYPE_CONV, PUSH_TYPE, PUSH_PENDING): New macros.
(verify_jvm_instruction): Use new macros, improving error messages.
For case OPCODE_astore use object_ptr_type_node.
* java-tree.h (TYPE_UNDERFLOW, TYPE_UNEXPECTED): New macros.
(pop_type_0, push_type_0, pop_argument_types): Update accordingly.
* parse.y (java_complete_lhs case EXPR_WITH_FILE_LOCATION): If body is * parse.y (java_complete_lhs case EXPR_WITH_FILE_LOCATION): If body is
constant, return body without wrapper. (Improves constant folding.) constant, return body without wrapper. (Improves constant folding.)
* lex.c (build_wfl_node): Clear TREE_TYPE from returned node. * lex.c (build_wfl_node): Clear TREE_TYPE from returned node.
......
...@@ -256,19 +256,31 @@ flush_quick_stack () ...@@ -256,19 +256,31 @@ flush_quick_stack ()
} }
} }
void /* Push TYPE on the type stack.
push_type (type) Return true on success, 0 on overflow. */
int
push_type_0 (type)
tree type; tree type;
{ {
int n_words; int n_words;
type = promote_type (type); type = promote_type (type);
n_words = 1 + TYPE_IS_WIDE (type); n_words = 1 + TYPE_IS_WIDE (type);
if (stack_pointer + n_words > DECL_MAX_STACK (current_function_decl)) if (stack_pointer + n_words > DECL_MAX_STACK (current_function_decl))
fatal ("stack overflow"); return 0;
stack_type_map[stack_pointer++] = type; stack_type_map[stack_pointer++] = type;
n_words--; n_words--;
while (--n_words >= 0) while (--n_words >= 0)
stack_type_map[stack_pointer++] = TYPE_SECOND; stack_type_map[stack_pointer++] = TYPE_SECOND;
return 1;
}
void
push_type (type)
tree type;
{
if (! push_type_0 (type))
fatal ("stack overflow");
} }
static void static void
...@@ -296,23 +308,32 @@ push_value (value) ...@@ -296,23 +308,32 @@ push_value (value)
/* Pop a type from the type stack. /* Pop a type from the type stack.
TYPE is the expected type. Return the actual type, which must be TYPE is the expected type. Return the actual type, which must be
convertible to TYPE, otherwise NULL_TREE is returned. */ convertible to TYPE.
On an error, *MESSAGEP is set to a freshly malloc'd error message. */
tree tree
pop_type_0 (type) pop_type_0 (type, messagep)
tree type; tree type;
char **messagep;
{ {
int n_words; int n_words;
tree t; tree t;
*messagep = NULL;
if (TREE_CODE (type) == RECORD_TYPE) if (TREE_CODE (type) == RECORD_TYPE)
type = promote_type (type); type = promote_type (type);
n_words = 1 + TYPE_IS_WIDE (type); n_words = 1 + TYPE_IS_WIDE (type);
if (stack_pointer < n_words) if (stack_pointer < n_words)
fatal ("stack underflow"); {
*messagep = xstrdup ("stack underflow");
return type;
}
while (--n_words > 0) while (--n_words > 0)
{ {
if (stack_type_map[--stack_pointer] != void_type_node) if (stack_type_map[--stack_pointer] != void_type_node)
fatal ("Invalid multi-word value on type stack"); {
*messagep = xstrdup ("Invalid multi-word value on type stack");
return type;
}
} }
t = stack_type_map[--stack_pointer]; t = stack_type_map[--stack_pointer];
if (type == NULL_TREE || t == type) if (type == NULL_TREE || t == type)
...@@ -334,7 +355,24 @@ pop_type_0 (type) ...@@ -334,7 +355,24 @@ pop_type_0 (type)
/* FIXME: this is worse than a kludge, probably. */ /* FIXME: this is worse than a kludge, probably. */
return object_ptr_type_node; return object_ptr_type_node;
} }
return NULL_TREE; {
const char *str1 = "expected type '";
const char *str3 = "' but stack contains '";
const char *str5 = "'";
int len1 = strlen (str1);
int len2 = strlen (lang_printable_name (type, 0));
int len3 = strlen (str3);
int len4 = strlen (lang_printable_name (t, 0));
int len5 = strlen (str5);
char *msg = xmalloc (len1 + len2 + len3 + len4 + len5 + 1);
*messagep = msg;
strcpy (msg, str1); msg += len1;
strcpy (msg, lang_printable_name (type, 0)); msg += len2;
strcpy (msg, str3); msg += len3;
strcpy (msg, lang_printable_name (t, 0)); msg += len4;
strcpy (msg, str5);
return type;
}
} }
/* Pop a type from the type stack. /* Pop a type from the type stack.
...@@ -345,10 +383,13 @@ tree ...@@ -345,10 +383,13 @@ tree
pop_type (type) pop_type (type)
tree type; tree type;
{ {
tree t = pop_type_0 (type); char *message = NULL;
if (t != NULL_TREE) type = pop_type_0 (type, &message);
return t; if (message != NULL)
error ("unexpected type on stack"); {
error (message);
free (message);
}
return type; return type;
} }
...@@ -1576,23 +1617,6 @@ expand_java_ret (return_address) ...@@ -1576,23 +1617,6 @@ expand_java_ret (return_address)
} }
#endif #endif
/* Recursive helper function to pop argument types during verifiation. */
void
pop_argument_types (arg_types)
tree arg_types;
{
if (arg_types == end_params_node)
return;
if (TREE_CODE (arg_types) == TREE_LIST)
{
pop_argument_types (TREE_CHAIN (arg_types));
pop_type (TREE_VALUE (arg_types));
return;
}
abort ();
}
static tree static tree
pop_arguments (arg_types) pop_arguments (arg_types)
tree arg_types; tree arg_types;
......
...@@ -978,9 +978,8 @@ extern tree build_java_array_type PARAMS ((tree, HOST_WIDE_INT)); ...@@ -978,9 +978,8 @@ extern tree build_java_array_type PARAMS ((tree, HOST_WIDE_INT));
extern int is_compiled_class PARAMS ((tree)); extern int is_compiled_class PARAMS ((tree));
extern tree mangled_classname PARAMS ((const char*, tree)); extern tree mangled_classname PARAMS ((const char*, tree));
extern tree lookup_label PARAMS ((int)); extern tree lookup_label PARAMS ((int));
extern tree pop_type_0 PARAMS ((tree)); extern tree pop_type_0 PARAMS ((tree, char**));
extern tree pop_type PARAMS ((tree)); extern tree pop_type PARAMS ((tree));
extern void pop_argument_types PARAMS ((tree));
extern tree decode_newarray_type PARAMS ((int)); extern tree decode_newarray_type PARAMS ((int));
extern tree lookup_field PARAMS ((tree*, tree)); extern tree lookup_field PARAMS ((tree*, tree));
extern int is_array_type_p PARAMS ((tree)); extern int is_array_type_p PARAMS ((tree));
...@@ -1057,6 +1056,7 @@ extern int process_jvm_instruction PARAMS ((int, const unsigned char *, long)); ...@@ -1057,6 +1056,7 @@ extern int process_jvm_instruction PARAMS ((int, const unsigned char *, long));
extern int maybe_adjust_start_pc PARAMS ((struct JCF *, int, int, int)); extern int maybe_adjust_start_pc PARAMS ((struct JCF *, int, int, int));
extern void set_local_type PARAMS ((int, tree)); extern void set_local_type PARAMS ((int, tree));
extern int merge_type_state PARAMS ((tree)); extern int merge_type_state PARAMS ((tree));
extern int push_type_0 PARAMS ((tree));
extern void push_type PARAMS ((tree)); extern void push_type PARAMS ((tree));
extern void load_type_state PARAMS ((tree)); extern void load_type_state PARAMS ((tree));
extern void add_interface PARAMS ((tree, tree)); extern void add_interface PARAMS ((tree, tree));
...@@ -1244,6 +1244,12 @@ extern int linenumber_count; ...@@ -1244,6 +1244,12 @@ extern int linenumber_count;
used nor set in the subroutine. */ used nor set in the subroutine. */
#define TYPE_UNUSED error_mark_node #define TYPE_UNUSED error_mark_node
/* When returned from pop_type_0, indicates stack underflow. */
#define TYPE_UNDERFLOW integer_zero_node
/* When returned from pop_type_0, indicates a type mismatch. */
#define TYPE_UNEXPECTED NULL_TREE
/* A array mapping variable/stack slot index to the type current /* A array mapping variable/stack slot index to the type current
in that variable/stack slot. in that variable/stack slot.
TYPE_UNKNOWN, TYPE_SECOND, and TYPE_NULL are special cases. */ TYPE_UNKNOWN, TYPE_SECOND, and TYPE_NULL are special cases. */
......
...@@ -348,9 +348,43 @@ start_pc_cmp (xp, yp) ...@@ -348,9 +348,43 @@ start_pc_cmp (xp, yp)
#define VERIFICATION_ERROR(MESSAGE) \ #define VERIFICATION_ERROR(MESSAGE) \
do { message = MESSAGE; goto verify_error; } while (0) do { message = MESSAGE; goto verify_error; } while (0)
/* Recursive helper function to pop argument types during verifiation.
ARG_TYPES is the list of formal parameter types.
Return NULL on success and a freshly malloc'd error message on failure. */
static char *
pop_argument_types (arg_types)
tree arg_types;
{
if (arg_types == end_params_node)
return NULL;
if (TREE_CODE (arg_types) == TREE_LIST)
{
char *message = pop_argument_types (TREE_CHAIN (arg_types));
if (message == NULL)
pop_type_0 (TREE_VALUE (arg_types), &message);
return message;
}
abort ();
}
#define POP_TYPE(TYPE, MESSAGE) \
do { pmessage = NULL; pop_type_0 (TYPE, &pmessage); \
if (pmessage != NULL) goto pop_type_error; \
} while (0)
#define POP_TYPE_CONV(TYPE, POPPED_TYPE, MESSAGE) \
do { pmessage = NULL; POPPED_TYPE = pop_type_0 (TYPE, &pmessage); \
if (pmessage != NULL) goto pop_type_error; \
} while (0)
#define PUSH_TYPE(TYPE) \
do { if (! push_type_0 (TYPE)) { goto stack_overflow; }} while (0)
#define PUSH_PENDING(LABEL) \ #define PUSH_PENDING(LABEL) \
do { if ((message = check_pending_block (LABEL)) != NULL) \ do { tree tmplab = LABEL; \
goto verify_error; } while (0) if ((message = check_pending_block (tmplab)) != NULL) \
{ oldpc = LABEL_PC (tmplab); goto verify_error; }} while (0)
#ifdef __GNUC__ #ifdef __GNUC__
#define CHECK_PC_IN_RANGE(PC) ({if (PC < 0 || PC > length) goto bad_pc; (void)1;}) #define CHECK_PC_IN_RANGE(PC) ({if (PC < 0 || PC > length) goto bad_pc; (void)1;})
...@@ -376,6 +410,7 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -376,6 +410,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
int oldpc = 0; /* PC of start of instruction. */ int oldpc = 0; /* PC of start of instruction. */
int prevpc = 0; /* If >= 0, PC of previous instruction. */ int prevpc = 0; /* If >= 0, PC of previous instruction. */
const char *message; const char *message;
char *pmessage;
int i; int i;
register unsigned char *p; register unsigned char *p;
struct eh_range *prev_eh_ranges = NULL_EH_RANGE; struct eh_range *prev_eh_ranges = NULL_EH_RANGE;
...@@ -559,13 +594,13 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -559,13 +594,13 @@ verify_jvm_instructions (jcf, byte_ops, length)
if (byte_ops[PC] == OPCODE_newarray if (byte_ops[PC] == OPCODE_newarray
|| byte_ops[PC] == OPCODE_newarray) || byte_ops[PC] == OPCODE_newarray)
int_value = i; int_value = i;
push_type (int_type_node); break; PUSH_TYPE (int_type_node); break;
case OPCODE_lconst_0: case OPCODE_lconst_1: case OPCODE_lconst_0: case OPCODE_lconst_1:
push_type (long_type_node); break; PUSH_TYPE (long_type_node); break;
case OPCODE_fconst_0: case OPCODE_fconst_1: case OPCODE_fconst_2: case OPCODE_fconst_0: case OPCODE_fconst_1: case OPCODE_fconst_2:
push_type (float_type_node); break; PUSH_TYPE (float_type_node); break;
case OPCODE_dconst_0: case OPCODE_dconst_1: case OPCODE_dconst_0: case OPCODE_dconst_1:
push_type (double_type_node); break; PUSH_TYPE (double_type_node); break;
case OPCODE_bipush: case OPCODE_bipush:
i = IMMEDIATE_s1; i = IMMEDIATE_s1;
goto push_int; goto push_int;
...@@ -616,13 +651,13 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -616,13 +651,13 @@ verify_jvm_instructions (jcf, byte_ops, length)
? (! INTEGRAL_TYPE_P (tmp) || TYPE_PRECISION (tmp) > 32) ? (! INTEGRAL_TYPE_P (tmp) || TYPE_PRECISION (tmp) > 32)
: type != tmp)) : type != tmp))
VERIFICATION_ERROR("invalid local variable type in load"); VERIFICATION_ERROR("invalid local variable type in load");
push_type (tmp); PUSH_TYPE (tmp);
goto note_used; goto note_used;
case OPCODE_istore: type = int_type_node; goto general_store; case OPCODE_istore: type = int_type_node; goto general_store;
case OPCODE_lstore: type = long_type_node; goto general_store; case OPCODE_lstore: type = long_type_node; goto general_store;
case OPCODE_fstore: type = float_type_node; goto general_store; case OPCODE_fstore: type = float_type_node; goto general_store;
case OPCODE_dstore: type = double_type_node; goto general_store; case OPCODE_dstore: type = double_type_node; goto general_store;
case OPCODE_astore: type = ptr_type_node; goto general_store; case OPCODE_astore: type = object_ptr_type_node; goto general_store;
general_store: general_store:
index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1; index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1;
wide = 0; wide = 0;
...@@ -655,7 +690,7 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -655,7 +690,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
VERIFICATION_ERROR ("invalid local variable index in store"); VERIFICATION_ERROR ("invalid local variable index in store");
return 0; return 0;
} }
type = pop_type (type); POP_TYPE_CONV (type, type, NULL);
type_map[index] = type; type_map[index] = type;
/* If local variable changed, we need to reconsider eh handlers. */ /* If local variable changed, we need to reconsider eh handlers. */
...@@ -723,19 +758,19 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -723,19 +758,19 @@ verify_jvm_instructions (jcf, byte_ops, length)
type = double_type_node; goto unop; type = double_type_node; goto unop;
unop: unop:
pop_type (type); pop_type (type);
push_type (type); PUSH_TYPE (type);
break; break;
binop: binop:
pop_type (type); pop_type (type);
pop_type (type); pop_type (type);
push_type (type); PUSH_TYPE (type);
break; break;
case OPCODE_lshl: case OPCODE_lshl:
case OPCODE_lshr: case OPCODE_lshr:
case OPCODE_lushr: case OPCODE_lushr:
pop_type (int_type_node); pop_type (int_type_node);
pop_type (long_type_node); pop_type (long_type_node);
push_type (long_type_node); PUSH_TYPE (long_type_node);
break; break;
case OPCODE_iinc: case OPCODE_iinc:
index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1; index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1;
...@@ -744,33 +779,34 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -744,33 +779,34 @@ verify_jvm_instructions (jcf, byte_ops, length)
if (index < 0 || index >= DECL_MAX_LOCALS (current_function_decl)) if (index < 0 || index >= DECL_MAX_LOCALS (current_function_decl))
VERIFICATION_ERROR ("invalid local variable index in iinc"); VERIFICATION_ERROR ("invalid local variable index in iinc");
tmp = type_map[index]; tmp = type_map[index];
if (! INTEGRAL_TYPE_P (tmp) || TYPE_PRECISION (tmp) > 32) if (tmp == NULL_TREE
|| ! INTEGRAL_TYPE_P (tmp) || TYPE_PRECISION (tmp) > 32)
VERIFICATION_ERROR ("invalid local variable type in iinc"); VERIFICATION_ERROR ("invalid local variable type in iinc");
break; break;
case OPCODE_i2l: case OPCODE_i2l:
pop_type (int_type_node); push_type (long_type_node); break; pop_type (int_type_node); PUSH_TYPE (long_type_node); break;
case OPCODE_i2f: case OPCODE_i2f:
pop_type (int_type_node); push_type (float_type_node); break; pop_type (int_type_node); PUSH_TYPE (float_type_node); break;
case OPCODE_i2d: case OPCODE_i2d:
pop_type (int_type_node); push_type (double_type_node); break; pop_type (int_type_node); PUSH_TYPE (double_type_node); break;
case OPCODE_l2i: case OPCODE_l2i:
pop_type (long_type_node); push_type (int_type_node); break; pop_type (long_type_node); PUSH_TYPE (int_type_node); break;
case OPCODE_l2f: case OPCODE_l2f:
pop_type (long_type_node); push_type (float_type_node); break; pop_type (long_type_node); PUSH_TYPE (float_type_node); break;
case OPCODE_l2d: case OPCODE_l2d:
pop_type (long_type_node); push_type (double_type_node); break; pop_type (long_type_node); PUSH_TYPE (double_type_node); break;
case OPCODE_f2i: case OPCODE_f2i:
pop_type (float_type_node); push_type (int_type_node); break; pop_type (float_type_node); PUSH_TYPE (int_type_node); break;
case OPCODE_f2l: case OPCODE_f2l:
pop_type (float_type_node); push_type (long_type_node); break; pop_type (float_type_node); PUSH_TYPE (long_type_node); break;
case OPCODE_f2d: case OPCODE_f2d:
pop_type (float_type_node); push_type (double_type_node); break; pop_type (float_type_node); PUSH_TYPE (double_type_node); break;
case OPCODE_d2i: case OPCODE_d2i:
pop_type (double_type_node); push_type (int_type_node); break; pop_type (double_type_node); PUSH_TYPE (int_type_node); break;
case OPCODE_d2l: case OPCODE_d2l:
pop_type (double_type_node); push_type (long_type_node); break; pop_type (double_type_node); PUSH_TYPE (long_type_node); break;
case OPCODE_d2f: case OPCODE_d2f:
pop_type (double_type_node); push_type (float_type_node); break; pop_type (double_type_node); PUSH_TYPE (float_type_node); break;
case OPCODE_lcmp: case OPCODE_lcmp:
type = long_type_node; goto compare; type = long_type_node; goto compare;
case OPCODE_fcmpl: case OPCODE_fcmpl:
...@@ -781,7 +817,7 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -781,7 +817,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
type = double_type_node; goto compare; type = double_type_node; goto compare;
compare: compare:
pop_type (type); pop_type (type); pop_type (type); pop_type (type);
push_type (int_type_node); break; PUSH_TYPE (int_type_node); break;
case OPCODE_ifeq: case OPCODE_ifeq:
case OPCODE_ifne: case OPCODE_ifne:
case OPCODE_iflt: case OPCODE_iflt:
...@@ -848,10 +884,7 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -848,10 +884,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
if (type != return_type) if (type != return_type)
VERIFICATION_ERROR ("incorrect ?return opcode"); VERIFICATION_ERROR ("incorrect ?return opcode");
if (type != void_type_node) if (type != void_type_node)
{ POP_TYPE(type, "return value has wrong type");
if (pop_type_0 (type) == NULL_TREE)
VERIFICATION_ERROR ("return value has wrong type");
}
INVALIDATE_PC; INVALIDATE_PC;
break; break;
case OPCODE_getstatic: is_putting = 0; is_static = 1; goto field; case OPCODE_getstatic: is_putting = 0; is_static = 1; goto field;
...@@ -864,22 +897,21 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -864,22 +897,21 @@ verify_jvm_instructions (jcf, byte_ops, length)
tree field_signature = COMPONENT_REF_SIGNATURE (&current_jcf->cpool, index); tree field_signature = COMPONENT_REF_SIGNATURE (&current_jcf->cpool, index);
tree field_type = get_type_from_signature (field_signature); tree field_type = get_type_from_signature (field_signature);
if (is_putting) if (is_putting)
pop_type (field_type); POP_TYPE (field_type, "incorrect type for field");
if (! is_static) if (! is_static)
{ {
int clindex = COMPONENT_REF_CLASS_INDEX (&current_jcf->cpool, int clindex = COMPONENT_REF_CLASS_INDEX (&current_jcf->cpool,
index); index);
tree self_type = get_class_constant (current_jcf, clindex); tree self_type = get_class_constant (current_jcf, clindex);
/* Defer actual checking until next pass. */ /* Defer actual checking until next pass. */
if (pop_type_0 (self_type) == NULL_TREE) POP_TYPE(self_type, "incorrect type for field reference");
VERIFICATION_ERROR ("incorrect type for field reference");
} }
if (! is_putting) if (! is_putting)
push_type (field_type); PUSH_TYPE (field_type);
break; break;
} }
case OPCODE_new: case OPCODE_new:
push_type (get_class_constant (jcf, IMMEDIATE_u2)); PUSH_TYPE (get_class_constant (jcf, IMMEDIATE_u2));
break; break;
case OPCODE_dup: type_stack_dup (1, 0); break; case OPCODE_dup: type_stack_dup (1, 0); break;
case OPCODE_dup_x1: type_stack_dup (1, 1); break; case OPCODE_dup_x1: type_stack_dup (1, 1); break;
...@@ -934,7 +966,7 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -934,7 +966,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
i = TREE_INT_CST_LOW (get_constant (current_jcf, index)); i = TREE_INT_CST_LOW (get_constant (current_jcf, index));
goto push_int; goto push_int;
} }
push_type (type); PUSH_TYPE (type);
break; break;
case OPCODE_invokevirtual: case OPCODE_invokevirtual:
...@@ -953,7 +985,12 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -953,7 +985,12 @@ verify_jvm_instructions (jcf, byte_ops, length)
IDENTIFIER_LENGTH (sig)); IDENTIFIER_LENGTH (sig));
if (TREE_CODE (method_type) != FUNCTION_TYPE) if (TREE_CODE (method_type) != FUNCTION_TYPE)
VERIFICATION_ERROR ("bad method signature"); VERIFICATION_ERROR ("bad method signature");
pop_argument_types (TYPE_ARG_TYPES (method_type)); pmessage = pop_argument_types (TYPE_ARG_TYPES (method_type));
if (pmessage != NULL)
{
message = "invalid argument type";
goto pop_type_error;
}
/* Can't invoke <clinit> */ /* Can't invoke <clinit> */
if (ID_CLINIT_P (method_name)) if (ID_CLINIT_P (method_name))
...@@ -963,7 +1000,8 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -963,7 +1000,8 @@ verify_jvm_instructions (jcf, byte_ops, length)
VERIFICATION_ERROR ("invoke opcode can't invoke <init>"); VERIFICATION_ERROR ("invoke opcode can't invoke <init>");
if (op_code != OPCODE_invokestatic) if (op_code != OPCODE_invokestatic)
pop_type (self_type); POP_TYPE (self_type,
"stack type not subclass of invoked method's class");
switch (op_code) switch (op_code)
{ {
...@@ -980,14 +1018,14 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -980,14 +1018,14 @@ verify_jvm_instructions (jcf, byte_ops, length)
} }
if (TREE_TYPE (method_type) != void_type_node) if (TREE_TYPE (method_type) != void_type_node)
push_type (TREE_TYPE (method_type)); PUSH_TYPE (TREE_TYPE (method_type));
break; break;
} }
case OPCODE_arraylength: case OPCODE_arraylength:
/* Type checking actually made during code generation */ /* Type checking actually made during code generation */
pop_type( ptr_type_node ); pop_type( ptr_type_node );
push_type( int_type_node ); PUSH_TYPE( int_type_node );
break; break;
/* Q&D verification *or* more checking done during code generation /* Q&D verification *or* more checking done during code generation
...@@ -1025,7 +1063,7 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -1025,7 +1063,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
type = TYPE_ARRAY_ELEMENT (TREE_TYPE (tmp)); type = TYPE_ARRAY_ELEMENT (TREE_TYPE (tmp));
else if (tmp != TYPE_NULL) else if (tmp != TYPE_NULL)
VERIFICATION_ERROR ("array load from non-array type"); VERIFICATION_ERROR ("array load from non-array type");
push_type (type); PUSH_TYPE (type);
break; break;
case OPCODE_anewarray: case OPCODE_anewarray:
...@@ -1061,7 +1099,7 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -1061,7 +1099,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
int_value = -1; int_value = -1;
type = build_java_array_type (type, int_value); type = build_java_array_type (type, int_value);
pop_type (int_type_node); pop_type (int_type_node);
push_type (type); PUSH_TYPE (type);
break; break;
case OPCODE_multianewarray: case OPCODE_multianewarray:
...@@ -1075,12 +1113,12 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -1075,12 +1113,12 @@ verify_jvm_instructions (jcf, byte_ops, length)
for( i = 0; i < ndim; i++ ) for( i = 0; i < ndim; i++ )
pop_type (int_type_node); pop_type (int_type_node);
push_type (get_class_constant (current_jcf, index)); PUSH_TYPE (get_class_constant (current_jcf, index));
break; break;
} }
case OPCODE_aconst_null: case OPCODE_aconst_null:
push_type (ptr_type_node); PUSH_TYPE (ptr_type_node);
break; break;
case OPCODE_athrow: case OPCODE_athrow:
...@@ -1092,12 +1130,12 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -1092,12 +1130,12 @@ verify_jvm_instructions (jcf, byte_ops, length)
case OPCODE_checkcast: case OPCODE_checkcast:
pop_type (ptr_type_node); pop_type (ptr_type_node);
type = get_class_constant (current_jcf, IMMEDIATE_u2); type = get_class_constant (current_jcf, IMMEDIATE_u2);
push_type (type); PUSH_TYPE (type);
break; break;
case OPCODE_instanceof: case OPCODE_instanceof:
pop_type (ptr_type_node); pop_type (ptr_type_node);
get_class_constant (current_jcf, IMMEDIATE_u2); get_class_constant (current_jcf, IMMEDIATE_u2);
push_type (int_type_node); PUSH_TYPE (int_type_node);
break; break;
case OPCODE_tableswitch: case OPCODE_tableswitch:
...@@ -1170,7 +1208,7 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -1170,7 +1208,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
{ {
tree target = lookup_label (oldpc + IMMEDIATE_s2); tree target = lookup_label (oldpc + IMMEDIATE_s2);
tree return_label = lookup_label (PC); tree return_label = lookup_label (PC);
push_type (return_address_type_node); PUSH_TYPE (return_address_type_node);
/* The return label chain will be null if this is the first /* The return label chain will be null if this is the first
time we've seen this jsr target. */ time we've seen this jsr target. */
if (LABEL_RETURN_LABEL (target) == NULL_TREE) if (LABEL_RETURN_LABEL (target) == NULL_TREE)
...@@ -1358,6 +1396,16 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -1358,6 +1396,16 @@ verify_jvm_instructions (jcf, byte_ops, length)
} }
} }
return 1; return 1;
pop_type_error:
error ("verification error at PC=%d", oldpc);
if (message != NULL)
error ("%s", message);
error ("%s", pmessage);
free (pmessage);
return 0;
stack_overflow:
message = "stack overflow";
goto verify_error;
bad_pc: bad_pc:
message = "program counter out of range"; message = "program counter out of range";
goto verify_error; goto verify_error;
......
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