summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbothner <bothner@138bc75d-0d04-0410-961f-82ee72b054a4>2001-01-14 21:48:10 +0000
committerbothner <bothner@138bc75d-0d04-0410-961f-82ee72b054a4>2001-01-14 21:48:10 +0000
commit3e02ce3031888cf1bff6c5ee5267510f5874a01a (patch)
treeb22806b6cbd1c6c8c4d9c0c81a071e2ded927cba
parent786c6b83c3028ecb4637cb1c7f9687491958e28f (diff)
downloadgcc-3e02ce3031888cf1bff6c5ee5267510f5874a01a.tar.gz
Various patches to emit better messages on verification errors.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@39019 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/java/ChangeLog15
-rw-r--r--gcc/java/expr.c82
-rw-r--r--gcc/java/java-tree.h10
-rw-r--r--gcc/java/verify.c142
4 files changed, 171 insertions, 78 deletions
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog
index 1a00840a2d0..538d4b1cc34 100644
--- a/gcc/java/ChangeLog
+++ b/gcc/java/ChangeLog
@@ -1,5 +1,20 @@
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
constant, return body without wrapper. (Improves constant folding.)
* lex.c (build_wfl_node): Clear TREE_TYPE from returned node.
diff --git a/gcc/java/expr.c b/gcc/java/expr.c
index ddfc473f797..abc5f69103f 100644
--- a/gcc/java/expr.c
+++ b/gcc/java/expr.c
@@ -256,19 +256,31 @@ flush_quick_stack ()
}
}
-void
-push_type (type)
+/* Push TYPE on the type stack.
+ Return true on success, 0 on overflow. */
+
+int
+push_type_0 (type)
tree type;
{
int n_words;
type = promote_type (type);
n_words = 1 + TYPE_IS_WIDE (type);
if (stack_pointer + n_words > DECL_MAX_STACK (current_function_decl))
- fatal ("stack overflow");
+ return 0;
stack_type_map[stack_pointer++] = type;
n_words--;
while (--n_words >= 0)
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
@@ -296,23 +308,32 @@ push_value (value)
/* Pop a type from the type stack.
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
-pop_type_0 (type)
+pop_type_0 (type, messagep)
tree type;
+ char **messagep;
{
int n_words;
tree t;
+ *messagep = NULL;
if (TREE_CODE (type) == RECORD_TYPE)
type = promote_type (type);
n_words = 1 + TYPE_IS_WIDE (type);
if (stack_pointer < n_words)
- fatal ("stack underflow");
+ {
+ *messagep = xstrdup ("stack underflow");
+ return type;
+ }
while (--n_words > 0)
{
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];
if (type == NULL_TREE || t == type)
@@ -334,7 +355,24 @@ pop_type_0 (type)
/* FIXME: this is worse than a kludge, probably. */
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.
@@ -345,10 +383,13 @@ tree
pop_type (type)
tree type;
{
- tree t = pop_type_0 (type);
- if (t != NULL_TREE)
- return t;
- error ("unexpected type on stack");
+ char *message = NULL;
+ type = pop_type_0 (type, &message);
+ if (message != NULL)
+ {
+ error (message);
+ free (message);
+ }
return type;
}
@@ -1576,23 +1617,6 @@ expand_java_ret (return_address)
}
#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
pop_arguments (arg_types)
tree arg_types;
diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h
index 510511eb219..3d0793d4d58 100644
--- a/gcc/java/java-tree.h
+++ b/gcc/java/java-tree.h
@@ -978,9 +978,8 @@ extern tree build_java_array_type PARAMS ((tree, HOST_WIDE_INT));
extern int is_compiled_class PARAMS ((tree));
extern tree mangled_classname PARAMS ((const char*, tree));
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 void pop_argument_types PARAMS ((tree));
extern tree decode_newarray_type PARAMS ((int));
extern tree lookup_field PARAMS ((tree*, tree));
extern int is_array_type_p PARAMS ((tree));
@@ -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 void set_local_type PARAMS ((int, tree));
extern int merge_type_state PARAMS ((tree));
+extern int push_type_0 PARAMS ((tree));
extern void push_type PARAMS ((tree));
extern void load_type_state PARAMS ((tree));
extern void add_interface PARAMS ((tree, tree));
@@ -1244,6 +1244,12 @@ extern int linenumber_count;
used nor set in the subroutine. */
#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
in that variable/stack slot.
TYPE_UNKNOWN, TYPE_SECOND, and TYPE_NULL are special cases. */
diff --git a/gcc/java/verify.c b/gcc/java/verify.c
index 463509a3949..23b30887e51 100644
--- a/gcc/java/verify.c
+++ b/gcc/java/verify.c
@@ -348,9 +348,43 @@ start_pc_cmp (xp, yp)
#define VERIFICATION_ERROR(MESSAGE) \
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) \
- do { if ((message = check_pending_block (LABEL)) != NULL) \
- goto verify_error; } while (0)
+ do { tree tmplab = LABEL; \
+ if ((message = check_pending_block (tmplab)) != NULL) \
+ { oldpc = LABEL_PC (tmplab); goto verify_error; }} while (0)
#ifdef __GNUC__
#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)
int oldpc = 0; /* PC of start of instruction. */
int prevpc = 0; /* If >= 0, PC of previous instruction. */
const char *message;
+ char *pmessage;
int i;
register unsigned char *p;
struct eh_range *prev_eh_ranges = NULL_EH_RANGE;
@@ -559,13 +594,13 @@ verify_jvm_instructions (jcf, byte_ops, length)
if (byte_ops[PC] == OPCODE_newarray
|| byte_ops[PC] == OPCODE_newarray)
int_value = i;
- push_type (int_type_node); break;
+ PUSH_TYPE (int_type_node); break;
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:
- push_type (float_type_node); break;
+ PUSH_TYPE (float_type_node); break;
case OPCODE_dconst_0: case OPCODE_dconst_1:
- push_type (double_type_node); break;
+ PUSH_TYPE (double_type_node); break;
case OPCODE_bipush:
i = IMMEDIATE_s1;
goto push_int;
@@ -616,13 +651,13 @@ verify_jvm_instructions (jcf, byte_ops, length)
? (! INTEGRAL_TYPE_P (tmp) || TYPE_PRECISION (tmp) > 32)
: type != tmp))
VERIFICATION_ERROR("invalid local variable type in load");
- push_type (tmp);
+ PUSH_TYPE (tmp);
goto note_used;
case OPCODE_istore: type = int_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_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:
index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1;
wide = 0;
@@ -655,7 +690,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
VERIFICATION_ERROR ("invalid local variable index in store");
return 0;
}
- type = pop_type (type);
+ POP_TYPE_CONV (type, type, NULL);
type_map[index] = type;
/* If local variable changed, we need to reconsider eh handlers. */
@@ -723,19 +758,19 @@ verify_jvm_instructions (jcf, byte_ops, length)
type = double_type_node; goto unop;
unop:
pop_type (type);
- push_type (type);
+ PUSH_TYPE (type);
break;
binop:
pop_type (type);
pop_type (type);
- push_type (type);
+ PUSH_TYPE (type);
break;
case OPCODE_lshl:
case OPCODE_lshr:
case OPCODE_lushr:
pop_type (int_type_node);
pop_type (long_type_node);
- push_type (long_type_node);
+ PUSH_TYPE (long_type_node);
break;
case OPCODE_iinc:
index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1;
@@ -744,33 +779,34 @@ verify_jvm_instructions (jcf, byte_ops, length)
if (index < 0 || index >= DECL_MAX_LOCALS (current_function_decl))
VERIFICATION_ERROR ("invalid local variable index in iinc");
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");
break;
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:
- 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:
- 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:
- 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:
- 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:
- 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:
- 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:
- 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:
- 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:
- 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:
- 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:
- 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:
type = long_type_node; goto compare;
case OPCODE_fcmpl:
@@ -781,7 +817,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
type = double_type_node; goto compare;
compare:
pop_type (type); pop_type (type);
- push_type (int_type_node); break;
+ PUSH_TYPE (int_type_node); break;
case OPCODE_ifeq:
case OPCODE_ifne:
case OPCODE_iflt:
@@ -848,10 +884,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
if (type != return_type)
VERIFICATION_ERROR ("incorrect ?return opcode");
if (type != void_type_node)
- {
- if (pop_type_0 (type) == NULL_TREE)
- VERIFICATION_ERROR ("return value has wrong type");
- }
+ POP_TYPE(type, "return value has wrong type");
INVALIDATE_PC;
break;
case OPCODE_getstatic: is_putting = 0; is_static = 1; goto field;
@@ -864,22 +897,21 @@ verify_jvm_instructions (jcf, byte_ops, length)
tree field_signature = COMPONENT_REF_SIGNATURE (&current_jcf->cpool, index);
tree field_type = get_type_from_signature (field_signature);
if (is_putting)
- pop_type (field_type);
+ POP_TYPE (field_type, "incorrect type for field");
if (! is_static)
{
int clindex = COMPONENT_REF_CLASS_INDEX (&current_jcf->cpool,
index);
tree self_type = get_class_constant (current_jcf, clindex);
/* Defer actual checking until next pass. */
- if (pop_type_0 (self_type) == NULL_TREE)
- VERIFICATION_ERROR ("incorrect type for field reference");
+ POP_TYPE(self_type, "incorrect type for field reference");
}
if (! is_putting)
- push_type (field_type);
+ PUSH_TYPE (field_type);
break;
}
case OPCODE_new:
- push_type (get_class_constant (jcf, IMMEDIATE_u2));
+ PUSH_TYPE (get_class_constant (jcf, IMMEDIATE_u2));
break;
case OPCODE_dup: type_stack_dup (1, 0); break;
case OPCODE_dup_x1: type_stack_dup (1, 1); break;
@@ -934,7 +966,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
i = TREE_INT_CST_LOW (get_constant (current_jcf, index));
goto push_int;
}
- push_type (type);
+ PUSH_TYPE (type);
break;
case OPCODE_invokevirtual:
@@ -953,7 +985,12 @@ verify_jvm_instructions (jcf, byte_ops, length)
IDENTIFIER_LENGTH (sig));
if (TREE_CODE (method_type) != FUNCTION_TYPE)
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> */
if (ID_CLINIT_P (method_name))
@@ -963,7 +1000,8 @@ verify_jvm_instructions (jcf, byte_ops, length)
VERIFICATION_ERROR ("invoke opcode can't invoke <init>");
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)
{
@@ -980,14 +1018,14 @@ verify_jvm_instructions (jcf, byte_ops, length)
}
if (TREE_TYPE (method_type) != void_type_node)
- push_type (TREE_TYPE (method_type));
+ PUSH_TYPE (TREE_TYPE (method_type));
break;
}
case OPCODE_arraylength:
/* Type checking actually made during code generation */
pop_type( ptr_type_node );
- push_type( int_type_node );
+ PUSH_TYPE( int_type_node );
break;
/* Q&D verification *or* more checking done during code generation
@@ -1025,7 +1063,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
type = TYPE_ARRAY_ELEMENT (TREE_TYPE (tmp));
else if (tmp != TYPE_NULL)
VERIFICATION_ERROR ("array load from non-array type");
- push_type (type);
+ PUSH_TYPE (type);
break;
case OPCODE_anewarray:
@@ -1061,7 +1099,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
int_value = -1;
type = build_java_array_type (type, int_value);
pop_type (int_type_node);
- push_type (type);
+ PUSH_TYPE (type);
break;
case OPCODE_multianewarray:
@@ -1075,12 +1113,12 @@ verify_jvm_instructions (jcf, byte_ops, length)
for( i = 0; i < ndim; i++ )
pop_type (int_type_node);
- push_type (get_class_constant (current_jcf, index));
+ PUSH_TYPE (get_class_constant (current_jcf, index));
break;
}
case OPCODE_aconst_null:
- push_type (ptr_type_node);
+ PUSH_TYPE (ptr_type_node);
break;
case OPCODE_athrow:
@@ -1092,12 +1130,12 @@ verify_jvm_instructions (jcf, byte_ops, length)
case OPCODE_checkcast:
pop_type (ptr_type_node);
type = get_class_constant (current_jcf, IMMEDIATE_u2);
- push_type (type);
+ PUSH_TYPE (type);
break;
case OPCODE_instanceof:
pop_type (ptr_type_node);
get_class_constant (current_jcf, IMMEDIATE_u2);
- push_type (int_type_node);
+ PUSH_TYPE (int_type_node);
break;
case OPCODE_tableswitch:
@@ -1170,7 +1208,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
{
tree target = lookup_label (oldpc + IMMEDIATE_s2);
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
time we've seen this jsr target. */
if (LABEL_RETURN_LABEL (target) == NULL_TREE)
@@ -1358,6 +1396,16 @@ verify_jvm_instructions (jcf, byte_ops, length)
}
}
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:
message = "program counter out of range";
goto verify_error;