⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 verify.c

📁 gcc-2.95.3 Linux下最常用的C编译器
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Handle verification of bytecoded methods for the GNU compiler for    the Java(TM) language.   Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING.  If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA.Java and all Java-based marks are trademarks or registered trademarksof Sun Microsystems, Inc. in the United States and other countries.The Free Software Foundation is independent of Sun Microsystems, Inc.  */#include "config.h"#include "system.h"#include "tree.h"#include "java-tree.h"#include "javaop.h"#include "java-opcodes.h"#include "jcf.h"#include "java-except.h"#include "toplev.h"static void push_pending_label PROTO ((tree));static tree merge_types PROTO ((tree, tree));extern int stack_pointer;/* During verification, start of the current subroutine (jsr target). */tree current_subr;/* A list of pending blocks, chained using  LABEL_PENDING_CHAIN.   A pending block is one that has LABEL_CHANGED set, which means   it requires (re-) verification. */tree pending_blocks;/* Append TARGET_LABEL to the pending_block stack unless already in it. */static voidpush_pending_label (target_label)      tree target_label;{  if (! LABEL_CHANGED (target_label))    {      LABEL_PENDING_CHAIN (target_label) = pending_blocks;      pending_blocks = target_label;      LABEL_CHANGED (target_label) = 1;    }}/* Note that TARGET_LABEL is a possible successor instruction.   Merge the type state etc.   Return NULL on sucess, or an error message on failure. */static const char *check_pending_block (target_label)     tree target_label;{  int changed = merge_type_state (target_label);  if (changed)    {      if (changed < 0)	return "types could not be merged";      push_pending_label (target_label);    }  if (current_subr == NULL)    {      if (LABEL_IN_SUBR (target_label))	return "might transfer control into subroutine";    }  else    {      if (LABEL_IN_SUBR (target_label))	{	  if (LABEL_SUBR_START (target_label) != current_subr)	    return "transfer out of subroutine";	}      else if (! LABEL_VERIFIED (target_label))	{	  LABEL_IN_SUBR (target_label) = 1;	  LABEL_SUBR_START (target_label) = current_subr;	}      else	return "transfer out of subroutine";    }  return NULL;}/* Return the "merged" types of TYPE1 and TYPE2.   If either is primitive, the other must match (after promotion to int).   For reference types, return the common super-class.   Return TYPE_UNKNOWN if the types cannot be merged. */   static treemerge_types (type1, type2)     tree type1, type2;{  if (type1 == type2)    return type1;  if (type1 == TYPE_UNKNOWN || type2 == TYPE_UNKNOWN      || type1 == TYPE_RETURN_ADDR || type2 == TYPE_RETURN_ADDR)    return TYPE_UNKNOWN;  if (TREE_CODE (type1) == POINTER_TYPE && TREE_CODE (type2) == POINTER_TYPE)    {      int depth1, depth2;      tree tt1, tt2;      /* ptr_type_node is only used for a null reference,	 which is compatible with any reference type. */      if (type1 == ptr_type_node || type2 == object_ptr_type_node)	return type2;      if (type2 == ptr_type_node || type1 == object_ptr_type_node)	return type1;      tt1 = HANDLE_TO_CLASS_TYPE (TREE_TYPE (type1));      tt2 = HANDLE_TO_CLASS_TYPE (TREE_TYPE (type2));      if (TYPE_ARRAY_P (tt1) || TYPE_ARRAY_P (tt2))	{	  if (TYPE_ARRAY_P (tt1) == TYPE_ARRAY_P (tt2))	    {	      tree el_type1 = TYPE_ARRAY_ELEMENT (tt1);	      tree el_type2 = TYPE_ARRAY_ELEMENT (tt2);	      tree el_type = NULL_TREE;	      if (el_type1 == el_type2)		el_type = el_type1;	      else if (TREE_CODE (el_type1) == POINTER_TYPE		       && TREE_CODE (el_type2) == POINTER_TYPE)		el_type = merge_types (el_type1, el_type2);	      if (el_type != NULL_TREE)		{		  HOST_WIDE_INT len1 = java_array_type_length (tt1);		  HOST_WIDE_INT len2 = java_array_type_length (tt2);		  if (len1 != len2)		    len1 = -1;		  else if (el_type1 == el_type2)		    return type1;		  return promote_type (build_java_array_type (el_type, len1));		}	    }	  return object_ptr_type_node;	}      if (CLASS_INTERFACE (TYPE_NAME (tt1)))	{	  if (CLASS_INTERFACE (TYPE_NAME (tt2)))	    {	      /* This is a kludge, but matches what Sun's verifier does.		 It can be tricked, but is safe as long as type errors		 (i.e. interface method calls) are caught at run-time. */	      return object_ptr_type_node;	    }	  else	    {	      if (can_widen_reference_to (tt2, tt1))		return type1;	      else		return TYPE_UNKNOWN;	    }	}      else if (CLASS_INTERFACE (TYPE_NAME (tt2)))	{	  if (can_widen_reference_to (tt1, tt2))	    return type2;	  else	    return TYPE_UNKNOWN;	}      type1 = tt1;      type2 = tt2;      depth1 = class_depth (type1);      depth2 = class_depth (type2);      for ( ; depth1 > depth2;  depth1--)	type1 = TYPE_BINFO_BASETYPE (type1, 0);      for ( ; depth2 > depth1;  depth2--)	type2 = TYPE_BINFO_BASETYPE (type2, 0);      while (type1 != type2)	{	  type1 = TYPE_BINFO_BASETYPE (type1, 0);	  type2 = TYPE_BINFO_BASETYPE (type2, 0);	}      return promote_type (type1);    }  if (INTEGRAL_TYPE_P (type1) && INTEGRAL_TYPE_P (type2)      && TYPE_PRECISION (type1) <= 32 && TYPE_PRECISION (type2) <= 32)    return int_type_node;  return TYPE_UNKNOWN;}/* Merge the current type state with that at LABEL.   Return -1 the the states are incompatible (i.e. on error),   0 if there was no change, and 1 if there was a change. */intmerge_type_state (label)     tree label;{  int nlocals = DECL_MAX_LOCALS(current_function_decl);  int cur_length = stack_pointer + nlocals;  tree vec = LABEL_TYPE_STATE (label);  tree return_map;  if (vec == NULL_TREE)    {      vec = make_tree_vec (cur_length);      LABEL_TYPE_STATE (label) = vec;      while (--cur_length >= 0)	TREE_VEC_ELT (vec, cur_length) = type_map [cur_length];      return 1;    }  else    {      int i;      int changed = 0;      if (LABEL_IS_SUBR_START (label) && LABEL_VERIFIED (label)	  && current_subr != label)	return_map = LABEL_RETURN_TYPE_STATE (label);      else	return_map = NULL_TREE;      if (TREE_VEC_LENGTH (vec) != cur_length)	{	  return -1;	}      for (i = 0; i < cur_length; i++)	{	  tree old_type = TREE_VEC_ELT (vec, i);	  tree new_type = merge_types (old_type, type_map [i]);	  if (TREE_VEC_ELT (vec, i) != new_type)	    {	      /* If there has been a change, note that since we must re-verify.		 However, if the label is the start of a subroutine,		 we don't care about local variables that are neither		 set nor used in the sub-routine. */	      if (return_map == NULL_TREE || i >= nlocals		  || TREE_VEC_ELT (return_map, i) != TYPE_UNUSED		  || (TYPE_IS_WIDE (new_type)		      && TREE_VEC_ELT (return_map, i+1) != TYPE_UNUSED))		changed = 1;	    }	  TREE_VEC_ELT (vec, i) = new_type;	  if (new_type == TYPE_UNKNOWN)	    {	      if (i >= nlocals)		return -1;	    }	  else if (TYPE_IS_WIDE (new_type))	    i++;	}      return changed;    }}/* Handle dup-like operations. */static voidtype_stack_dup (size, offset)     int size, offset;{  tree type[4];  int index;  if (size + offset > stack_pointer)    error ("stack underflow - dup* operation");  for (index = 0;  index < size + offset; index++)    {      type[index] = stack_type_map[stack_pointer - 1];      if (type[index] == void_type_node)	{	  index++;	  type[index] = stack_type_map[stack_pointer - 2];	  if (! TYPE_IS_WIDE (type[index]))	    fatal ("internal error - dup operation");	  if (index == size || index == size + offset)	    fatal ("dup operation splits 64-bit number");	}      pop_type (type[index]);    }  for (index = size;  --index >= 0; )    {      if (type[index] != void_type_node)	push_type (type[index]);    }  for (index = size + offset;  --index >= 0; )    {      if (type[index] != void_type_node)	push_type (type[index]);    }}/* This keeps track of a start PC and corresponding initial index.  */struct pc_index{  int start_pc;  int index;};/* A helper that is used when sorting exception ranges.  */static intstart_pc_cmp (xp, yp)     const GENERIC_PTR xp;     const GENERIC_PTR yp;{  struct pc_index *x = (struct pc_index *) xp;  struct pc_index *y = (struct pc_index *) yp;  return x->start_pc - y->start_pc;}/* This causes the next iteration to ignore the next instruction   and look for some other unhandled instruction. */#define INVALIDATE_PC (prevpc = -1, oldpc = PC, PC = INVALID_PC)#define INVALID_PC (-1)#define VERIFICATION_ERROR(MESSAGE) \  do { message = MESSAGE;  goto verify_error; } while (0)#define PUSH_PENDING(LABEL) \     do { if ((message = check_pending_block (LABEL)) != NULL) \             goto verify_error; } while (0)#ifdef __GNUC__#define CHECK_PC_IN_RANGE(PC) ({if (PC < 0 || PC > length) goto bad_pc; 1;})#else#define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > length ? \  (fatal("Bad byte codes.\n"), 0) : 1)#endif#define BCODE byte_ops/* Verify the bytecodes of the current method.   Return 1 on sucess, 0 on failure. */intverify_jvm_instructions (jcf, byte_ops, length)     JCF* jcf;     unsigned char* byte_ops;     long length;{  tree label;  int wide = 0;  int op_code;  int PC;  int oldpc; /* PC of start of instruction. */  int prevpc;  /* If >= 0, PC of previous instruction. */  const char *message;  int i;  register unsigned char *p;  struct eh_range *prev_eh_ranges = NULL_EH_RANGE;  struct eh_range *eh_ranges;  tree return_type = TREE_TYPE (TREE_TYPE (current_function_decl));  struct pc_index *starts;  int eh_count;  jint int_value = -1;  pending_blocks = NULL_TREE;  /* Handle the exception table. */  method_init_exceptions ();  JCF_SEEK (jcf, DECL_CODE_OFFSET (current_function_decl) + length);  eh_count = JCF_readu2 (jcf);  /* We read the exception handlers in order of increasing start PC.     To do this we first read and sort the start PCs.  */  starts = (struct pc_index *) xmalloc (eh_count * sizeof (struct pc_index));  for (i = 0; i < eh_count; ++i)    {      starts[i].start_pc = GET_u2 (jcf->read_ptr + 8 * i);      starts[i].index = i;    }  qsort (starts, eh_count, sizeof (struct pc_index), start_pc_cmp);  for (i = 0; i < eh_count; ++i)    {      int start_pc, end_pc, handler_pc, catch_type;      p = jcf->read_ptr + 8 * starts[i].index;      start_pc = GET_u2 (p);      end_pc = GET_u2 (p+2);      handler_pc = GET_u2 (p+4);      catch_type = GET_u2 (p+6);      if (start_pc < 0 || start_pc >= length	  || end_pc < 0 || end_pc > length || start_pc >= end_pc	  || handler_pc < 0 || handler_pc >= length	  || (handler_pc >= start_pc && handler_pc < end_pc)	  || ! (instruction_bits [start_pc] & BCODE_INSTRUCTION_START)	  || ! (instruction_bits [end_pc] & BCODE_INSTRUCTION_START)	  || ! (instruction_bits [handler_pc] & BCODE_INSTRUCTION_START))	{	  error ("bad pc in exception_table");	  free (starts);	  return 0;	}      add_handler (start_pc, end_pc,		   lookup_label (handler_pc),		   catch_type == 0 ? NULL_TREE		   : get_class_constant (jcf, catch_type));      instruction_bits [handler_pc] |= BCODE_EXCEPTION_TARGET;    }  free (starts);  handle_nested_ranges ();  for (PC = 0;;)    {      int index;      tree type, tmp;      if (((PC != INVALID_PC	   && instruction_bits [PC] & BCODE_TARGET) != 0)	  || PC == 0)	{	  PUSH_PENDING (lookup_label (PC));	  INVALIDATE_PC;	}      /* Check if there are any more pending blocks in the current	 subroutine.  Because we push pending blocks in a	 last-in-first-out order, and because we don't push anything	 from our caller until we are done with this subroutine or	 anything nested in it, 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);	      

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -