📄 verify.c
字号:
case CONSTANT_String: type = string_type_node; goto check_ldc; case CONSTANT_Long: type = long_type_node; goto check_ldc; case CONSTANT_Double: type = double_type_node; goto check_ldc; check_ldc: if (TYPE_IS_WIDE (type) == (op_code == OPCODE_ldc2_w)) break; /* ... else fall through ... */ default: VERIFICATION_ERROR ("bad constant pool tag in ldc"); } if (type == int_type_node) { i = TREE_INT_CST_LOW (get_constant (current_jcf, index)); goto push_int; } push_type (type); break; case OPCODE_invokevirtual: case OPCODE_invokespecial: case OPCODE_invokestatic: case OPCODE_invokeinterface: { int index = IMMEDIATE_u2; tree sig = COMPONENT_REF_SIGNATURE (¤t_jcf->cpool, index); tree self_type = get_class_constant (current_jcf, COMPONENT_REF_CLASS_INDEX (¤t_jcf->cpool, index)); tree method_name = COMPONENT_REF_NAME (¤t_jcf->cpool, index); tree method_type; method_type = parse_signature_string (IDENTIFIER_POINTER (sig), IDENTIFIER_LENGTH (sig)); if (TREE_CODE (method_type) != FUNCTION_TYPE) VERIFICATION_ERROR ("bad method signature"); pop_argument_types (TYPE_ARG_TYPES (method_type)); /* Can't invoke <clinit> */ if (method_name == clinit_identifier_node) VERIFICATION_ERROR ("invoke opcode can't invoke <clinit>"); /* Apart invokespecial, can't invoke <init> */ if (op_code != OPCODE_invokespecial && method_name == init_identifier_node) VERIFICATION_ERROR ("invoke opcode can't invoke <init>"); if (op_code != OPCODE_invokestatic) pop_type (self_type); switch (op_code) { case OPCODE_invokeinterface: { int nargs = IMMEDIATE_u1; int notZero = IMMEDIATE_u1; if (!nargs || notZero) VERIFICATION_ERROR ("invalid argument number in invokeinterface"); break; } } if (TREE_TYPE (method_type) != void_type_node) 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 ); break; /* Q&D verification *or* more checking done during code generation for byte/boolean/char/short, the value popped is a int coerced into the right type before being stored. */ case OPCODE_iastore: type = int_type_node; goto astore; case OPCODE_lastore: type = long_type_node; goto astore; case OPCODE_fastore: type = float_type_node; goto astore; case OPCODE_dastore: type = double_type_node; goto astore; case OPCODE_aastore: type = ptr_type_node; goto astore; case OPCODE_bastore: type = int_type_node; goto astore; case OPCODE_castore: type = int_type_node; goto astore; case OPCODE_sastore: type = int_type_node; goto astore; astore: /* FIXME - need better verification here */ pop_type (type); /* new value */ pop_type (int_type_node); /* index */ pop_type (ptr_type_node); /* array */ break; /* Q&D verification *or* more checking done during code generation for byte/boolean/char/short, the value pushed is a int. */ case OPCODE_iaload: type = int_type_node; goto aload; case OPCODE_laload: type = long_type_node; goto aload; case OPCODE_faload: type = float_type_node; goto aload; case OPCODE_daload: type = double_type_node; goto aload; case OPCODE_aaload: type = ptr_type_node; goto aload; case OPCODE_baload: type = promote_type (byte_type_node); goto aload; case OPCODE_caload: type = promote_type (char_type_node); goto aload; case OPCODE_saload: type = promote_type (short_type_node); goto aload; aload: pop_type (int_type_node); tmp = pop_type (ptr_type_node); if (is_array_type_p (tmp)) type = TYPE_ARRAY_ELEMENT (TREE_TYPE (tmp)); else if (tmp != TYPE_NULL) VERIFICATION_ERROR ("array load from non-array type"); push_type (type); break; case OPCODE_anewarray: type = get_class_constant (current_jcf, IMMEDIATE_u2); type = promote_type (type); goto newarray; case OPCODE_newarray: index = IMMEDIATE_u1; type = decode_newarray_type (index); if (type == NULL_TREE) VERIFICATION_ERROR ("invalid type code in newarray opcode"); goto newarray; newarray: if (int_value >= 0 && prevpc >= 0) { /* If previous instruction pushed int constant, we want to use it. */ switch (byte_ops[prevpc]) { case OPCODE_iconst_0: case OPCODE_iconst_1: case OPCODE_iconst_2: case OPCODE_iconst_3: case OPCODE_iconst_4: case OPCODE_iconst_5: case OPCODE_bipush: case OPCODE_sipush: case OPCODE_ldc: case OPCODE_ldc_w: break; default: int_value = -1; } } else int_value = -1; type = build_java_array_type (type, int_value); pop_type (int_type_node); push_type (type); break; case OPCODE_multianewarray: { int ndim, i; index = IMMEDIATE_u2; ndim = IMMEDIATE_u1; if( ndim < 1 ) VERIFICATION_ERROR ("number of dimension lower that 1 in multianewarray" ); for( i = 0; i < ndim; i++ ) pop_type (int_type_node); push_type (get_class_constant (current_jcf, index)); break; } case OPCODE_aconst_null: push_type (ptr_type_node); break; case OPCODE_athrow: // FIXME: athrow also empties the stack. pop_type (throwable_type_node); INVALIDATE_PC; break; case OPCODE_checkcast: pop_type (ptr_type_node); type = get_class_constant (current_jcf, IMMEDIATE_u2); push_type (type); break; case OPCODE_instanceof: pop_type (ptr_type_node); get_class_constant (current_jcf, IMMEDIATE_u2); push_type (int_type_node); break; case OPCODE_tableswitch: { jint low, high; pop_type (int_type_node); while (PC%4) { if (byte_ops[PC++]) VERIFICATION_ERROR ("bad alignment in tableswitch pad"); } PUSH_PENDING (lookup_label (oldpc+IMMEDIATE_s4)); low = IMMEDIATE_s4; high = IMMEDIATE_s4; if (low > high) VERIFICATION_ERROR ("unsorted low/high value in tableswitch"); while (low++ <= high) PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4)); INVALIDATE_PC; break; } case OPCODE_lookupswitch: { jint npairs, last, not_registered = 1; pop_type (int_type_node); while (PC%4) { if (byte_ops[PC++]) VERIFICATION_ERROR ("bad alignment in lookupswitch pad"); } PUSH_PENDING (lookup_label (oldpc+IMMEDIATE_s4)); npairs = IMMEDIATE_s4; if (npairs < 0) VERIFICATION_ERROR ("invalid number of targets in lookupswitch"); while (npairs--) { int match = IMMEDIATE_s4; if (not_registered) not_registered = 0; else if (last >= match) VERIFICATION_ERROR ("unsorted match value in lookupswitch"); last = match; PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4)); } INVALIDATE_PC; break; } case OPCODE_monitorenter: /* fall thru */ case OPCODE_monitorexit: pop_type (ptr_type_node); break; case OPCODE_goto_w: PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4)); INVALIDATE_PC; break; case OPCODE_jsr: { tree target = lookup_label (oldpc + IMMEDIATE_s2); tree return_label = lookup_label (PC); push_type (return_address_type_node); if (! LABEL_VERIFIED (target)) { /* first time seen */ tree return_type_map; int nlocals = DECL_MAX_LOCALS (current_function_decl); index = nlocals + DECL_MAX_STACK (current_function_decl); return_type_map = make_tree_vec (index); while (index > nlocals) TREE_VEC_ELT (return_type_map, --index) = TYPE_UNKNOWN; while (index > 0) TREE_VEC_ELT (return_type_map, --index) = TYPE_UNUSED; LABEL_RETURN_LABEL (target) = build_decl (LABEL_DECL, NULL_TREE, TREE_TYPE (target)); LABEL_PC (LABEL_RETURN_LABEL (target)) = -1; LABEL_RETURN_TYPE_STATE (target) = return_type_map; LABEL_IS_SUBR_START (target) = 1; LABEL_IN_SUBR (target) = 1; LABEL_SUBR_START (target) = target; LABEL_SUBR_CONTEXT (target) = current_subr; } else if (! LABEL_IS_SUBR_START (target) || LABEL_SUBR_CONTEXT (target) != current_subr) VERIFICATION_ERROR ("label part of different subroutines"); i = merge_type_state (target); if (i != 0) { if (i < 0) VERIFICATION_ERROR ("types could not be merged at jsr"); push_pending_label (target); } current_subr = target; /* Chain return_pc onto LABEL_RETURN_LABELS (target) if needed. */ if (! value_member (return_label, LABEL_RETURN_LABELS (target))) { LABEL_RETURN_LABELS (target) = tree_cons (NULL_TREE, return_label, LABEL_RETURN_LABELS (target)); } if (LABEL_VERIFIED (target)) { tree return_map = LABEL_RETURN_TYPE_STATE (target); int len = TREE_VEC_LENGTH (return_map); stack_pointer = len - DECL_MAX_LOCALS (current_function_decl); while (--len >= 0) { if (TREE_VEC_ELT (return_map, len) != TYPE_UNUSED) type_map[len] = TREE_VEC_ELT (return_map, len); } current_subr = LABEL_SUBR_CONTEXT (target); PUSH_PENDING (return_label); } INVALIDATE_PC; } break; case OPCODE_ret: if (current_subr == NULL) VERIFICATION_ERROR ("ret instruction not in a jsr subroutine"); else { tree ret_map = LABEL_RETURN_TYPE_STATE (current_subr); tree caller = LABEL_SUBR_CONTEXT (current_subr); int size = DECL_MAX_LOCALS(current_function_decl)+stack_pointer; index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1; wide = 0; INVALIDATE_PC; if (index < 0 || index >= DECL_MAX_LOCALS (current_function_decl) || type_map[index] != TYPE_RETURN_ADDR) VERIFICATION_ERROR ("invalid ret index"); /* The next chunk of code is similar to an inlined version of * merge_type_state (LABEL_RETURN_LABEL (current_subr)). * The main differences are that LABEL_RETURN_LABEL is * pre-allocated by the jsr (but we don't know the size then); * and that we have to handle TYPE_UNUSED. */ if (! RETURN_MAP_ADJUSTED (ret_map)) { /* First return from this subroutine - fix stack pointer. */ TREE_VEC_LENGTH (ret_map) = size; for (index = size; --index >= 0; ) { if (TREE_VEC_ELT (ret_map, index) != TYPE_UNUSED) TREE_VEC_ELT (ret_map, index) = type_map[index]; } RETURN_MAP_ADJUSTED (ret_map) = 1; } else { if (TREE_VEC_LENGTH (ret_map) != size) VERIFICATION_ERROR ("inconsistent stack size on ret"); for (index = 0; index < size; index++) { tree type = TREE_VEC_ELT (ret_map, index); if (type != TYPE_UNUSED) { type = merge_types (type, type_map [index]); TREE_VEC_ELT (ret_map, index) = type; if (type == TYPE_UNKNOWN) { if (index >= size - stack_pointer) VERIFICATION_ERROR ("inconsistent types on ret from jsr"); } else if (TYPE_IS_WIDE (type)) index++; } } } } break; case OPCODE_jsr_w: case OPCODE_ret_w: default: error ("unknown opcode %d@pc=%d during verification", op_code, PC-1); return 0; } prevpc = oldpc; /* The following test is true if we have entered or exited an exception handler range *or* we have done a store to a local variable. In either case we need to consider any exception handlers that might "follow" this instruction. */ if (eh_ranges != prev_eh_ranges) { int save_stack_pointer = stack_pointer; int index = DECL_MAX_LOCALS (current_function_decl); tree save_type = type_map[index]; tree save_current_subr = current_subr; struct eh_range *ranges = find_handler (oldpc); stack_pointer = 1; for (; ranges != NULL_EH_RANGE; ranges = ranges->outer) { tree chain = ranges->handlers; /* We need to determine if the handler is part of current_subr. The are two cases: (1) The exception catch range is entirely within current_subr. In that case the handler is also part of current_subr. (2) Some of the catch range is not in current_subr. In that case, the handler is *not* part of current_subr. Figuring out which is the case is not necessarily obvious, in the presence of clever code generators (and obfuscators). We make a simplifying assumption that in case (2) we have that the current_subr is entirely within the catch range. In that case we can assume if that if a caller (the jsr) of a subroutine is within the catch range, then the handler is *not* part of the subroutine, and vice versa. */ current_subr = save_current_subr; for ( ; current_subr != NULL_TREE; current_subr = LABEL_SUBR_CONTEXT (current_subr)) { tree return_labels = LABEL_RETURN_LABELS (current_subr); /* There could be multiple return_labels, but we only need to check one. */ int return_pc = LABEL_PC (TREE_VALUE (return_labels)); if (return_pc <= ranges->start_pc || return_pc > ranges->end_pc) break; } for ( ; chain != NULL_TREE; chain = TREE_CHAIN (chain)) { tree handler = TREE_VALUE (chain); tree type = TREE_PURPOSE (chain); if (type == NULL_TREE) /* a finally handler */ type = throwable_type_node; type_map[index] = promote_type (type); PUSH_PENDING (handler); } } stack_pointer = save_stack_pointer; current_subr = save_current_subr; type_map[index] = save_type; prev_eh_ranges = eh_ranges; } } return 1; bad_pc: message = "program counter out of range"; goto verify_error; verify_error: error ("verification error at PC=%d", oldpc); error (message); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -