verifycode.c

来自「This is a resource based on j2me embedde」· C语言 代码 · 共 1,993 行 · 第 1/5 页

C
1,993
字号
 * Because a piece of code can possibly be reached through multiple subroutine calls (think * nested try...finally blocks), we have to compute one of these masks for each * path. Thus each struct mask_type has an entry field, giving the instruction number of * a subroutine entry point, i.e. an instruction which is the target of a jsr. */struct mask_type {    int entry;    int *modifies;};typedef unsigned short flag_type;/* * Before any dataflow is done, the instructions are unpacked into struct instruction_data_type. * Some opcodes are folded together because it is not important to distinguish between them, * and at lease one opcode is split off as a special case: opc_invokeinit. * Operands are broken out and unpacked. * During the course of computation, additional information is added (see use of operand2 * for the jsr), and it is decorated with the entire state of the computation BEFORE EXECUTION * of the instruction. * All references to the instruction stream are converted into instruction numbers, which are * indexes into an array of this structure. */struct instruction_data_type {    opcode_type opcode;		/* may turn into "canonical" opcode */    unsigned changed:1;		/* has it changed */    unsigned protected:1;	/* must accessor be a subclass of "this" */    union {	int i;			/* operand to the opcode */	int *ip;	fullinfo_type fi;    } operand, operand2;    fullinfo_type p;    struct stack_info_type stack_info;    struct register_info_type register_info;#define FLAG_REACHED            0x01 /* instruction reached */#define FLAG_NEED_CONSTRUCTOR   0x02 /* must call this.<init> or super.<init> */#define FLAG_NO_RETURN          0x04 /* must throw out of method */    flag_type or_flags;		/* true for at least one path to this inst */#define FLAG_CONSTRUCTED        0x01 /* this.<init> or super.<init> called */    flag_type and_flags;	/* true for all paths to this instruction */};/* * As in a class file, a handler has a starting and ending range and a beginning, * but this has then as instruction indexes. The initial stack is always * a single item of the class type being caught by the handler. */struct handler_info_type {    int start, end, handler;    struct stack_info_type stack_info;};/* * See struct stack_info_type above, which has a pointer to a linked list of these. */struct stack_item_type {    fullinfo_type item;    struct stack_item_type *next;};typedef struct context_type context_type;typedef struct instruction_data_type instruction_data_type;typedef struct stack_item_type stack_item_type;typedef struct register_info_type register_info_type;typedef struct stack_info_type stack_info_type;typedef struct mask_type mask_type;static void verify_method(context_type *context, CVMClassBlock *cb,			  CVMMethodBlock *mb);#if 0 /* See comment in verify_field(). */static void verify_field(context_type *context, CVMClassBlock *cb,			 CVMFieldBlock *fb);#endifstatic void verify_opcode_operands (context_type *, int inumber, int offset);static void set_protected(context_type *, int inumber, int key, opcode_type);static jboolean is_superclass(context_type *, fullinfo_type);static void initialize_exception_table(context_type *);static jboolean isLegalTarget(context_type *, int offset);static void verify_constant_pool_type(context_type *, int, unsigned);static void initialize_dataflow(context_type *);static void run_dataflow(context_type *context);static void check_register_values(context_type *context, int inumber);static void check_flags(context_type *context, int inumber);static void pop_stack(context_type *, int inumber, stack_info_type *);static void update_registers(context_type *, int inumber, register_info_type *);static void update_flags(context_type *, int inumber, 			 flag_type *new_and_flags, flag_type *new_or_flags);static void push_stack(context_type *, int inumber, stack_info_type *stack);static void merge_into_successors(context_type *, int inumber, 				  register_info_type *register_info,				  stack_info_type *stack_info, 				  flag_type and_flags, flag_type or_flags);static void merge_into_one_successor(context_type *context, 				     int from_inumber, int inumber, 				     register_info_type *register_info,				     stack_info_type *stack_info, 				     flag_type and_flags, flag_type or_flags,				     jboolean isException);static void merge_stack(context_type *, int inumber, int to_inumber, 			stack_info_type *);static void merge_registers(context_type *, int inumber, int to_inumber, 			    register_info_type *);static void merge_flags(context_type *context, int from_inumber, int to_inumber,			flag_type new_and_flags, flag_type new_or_flags);static stack_item_type *copy_stack(context_type *, stack_item_type *);static mask_type *copy_masks(context_type *, mask_type *masks, int mask_count);static mask_type *add_to_masks(context_type *, mask_type *, int , int);static fullinfo_type decrement_indirection(fullinfo_type);static fullinfo_type merge_fullinfo_types(context_type *context, 					  fullinfo_type a, 					  fullinfo_type b,					  jboolean assignment);static jboolean isAssignableTo(context_type *,			       fullinfo_type a, 			       fullinfo_type b);static CVMClassBlock *object_fullinfo_to_classclass(context_type *, fullinfo_type);#define NEW(type, count) \        ((type *)CCalloc(context, (count)*(sizeof(type)), JNI_FALSE))#define ZNEW(type, count) \        ((type *)CCalloc(context, (count)*(sizeof(type)), JNI_TRUE))static void CCinit(context_type *context);static void CCreinit(context_type *context);static void CCdestroy(context_type *context);static void *CCalloc(context_type *context, int size, jboolean zero);static fullinfo_type cp_index_to_class_fullinfo(context_type *, int, int);static char signature_to_fieldtype(context_type *context, 				   CVMFieldTypeID fieldID,				   fullinfo_type *info);static void CCerror (context_type *, char *format, ...);static void CCout_of_memory (context_type *);#ifdef CVM_TRACEstatic void print_stack (context_type *, stack_info_type *stack_info);static void print_registers(context_type *, register_info_type *register_info);static void print_flags(context_type *, flag_type, flag_type);static void print_formatted_fieldname(context_type *context, int index);static void print_formatted_methodname(context_type *context, int index);#endifstatic void initialize_class_hash(context_type *context) {    hash_table_type *class_hash = &(context->class_hash);    class_hash->buckets = (hash_bucket_type **)        calloc(MAX_HASH_ENTRIES / HASH_ROW_SIZE, sizeof(hash_bucket_type *));    class_hash->table = (unsigned short *)        calloc(HASH_TABLE_SIZE, sizeof(unsigned short));    if (class_hash->buckets == 0 ||	class_hash->table == 0)        CCout_of_memory(context);    class_hash->entries_used = 0;}static void finalize_class_hash(context_type *context){    hash_table_type *class_hash = &(context->class_hash);    int i;    if (class_hash->buckets) {        for (i=0;i<MAX_HASH_ENTRIES / HASH_ROW_SIZE; i++) {	    if (class_hash->buckets[i] == 0)	        break;	    free(class_hash->buckets[i]);	}    }    free(class_hash->buckets);    free(class_hash->table);}static hash_bucket_type * new_bucket(context_type *context, unsigned short *pID){    hash_table_type *class_hash = &(context->class_hash);    int i = *pID = class_hash->entries_used + 1;    int row = i / HASH_ROW_SIZE;    if (i >= MAX_HASH_ENTRIES)        CCerror(context, "Exceeded verifier's limit of 65535 referred classes");    if (class_hash->buckets[row] == 0) {        class_hash->buckets[row] = (hash_bucket_type*)	    calloc(HASH_ROW_SIZE, sizeof(hash_bucket_type));	if (class_hash->buckets[row] == 0)	    CCout_of_memory(context);    }    class_hash->entries_used++; /* only increment when we are sure there				   is no overflow. */    return GET_BUCKET(class_hash, i);}/* * Find a class using the defining loader of the current class * and return a local reference to it. */static CVMClassBlock*load_class_local(context_type *context, CVMClassTypeID classname){    CVMClassBlock *cb = 	CVMclassLookupByTypeFromClass(context->ee, classname, CVM_FALSE, 				      context->class);    if (cb == 0)	 CCerror(context, "Cannot find class %!C", classname);    return cb;} /* * Find a class using the defining loader of the current class * and return a global reference to it. */static CVMClassBlock *load_class_global(context_type *context, CVMClassTypeID classname){    return load_class_local(context, classname);} /* * Return a unique ID given a local class reference. The loadable * flag is true if the defining class loader of context->class * is known to be capable of loading the class. */static int class_to_ID(context_type *context, CVMClassBlock *cb, jboolean loadable){    hash_table_type *class_hash = &(context->class_hash);    unsigned int hash;    hash_bucket_type *bucket;    unsigned short *pID;    CVMClassTypeID name = CVMcbClassName(cb);    hash = name;    pID = &(class_hash->table[hash % HASH_TABLE_SIZE]);    while (*pID) {        bucket = GET_BUCKET(class_hash, *pID);        if (name == bucket->name) {	    /*	     * There is an unresolved entry with our name	     * so we're forced to load it in case it matches us.	     */	    if (bucket->class == 0) {		CVMassert(bucket->loadable == JNI_TRUE);		bucket->class = load_class_global(context, name);	    }	    /*	     * It's already in the table. Update the loadable	     * state if it's known and then we're done.	     */	    if (cb == bucket->class) {		if (loadable && !bucket->loadable)		    bucket->loadable = JNI_TRUE;	        goto done;	    }	}	pID = &bucket->next;    }    bucket = new_bucket(context, pID);    bucket->next = 0;    bucket->name = name;    bucket->loadable = loadable;    bucket->class = cb;done:    return *pID;}/* * Return a unique ID given a class name from the constant pool. * All classes are lazily loaded from the defining loader of * context->class. */static int class_name_to_ID(context_type *context, CVMClassTypeID name){    hash_table_type *class_hash = &(context->class_hash);    unsigned int hash = name;    hash_bucket_type *bucket;    unsigned short *pID;    jboolean force_load = JNI_FALSE;    CVMassert(name == CVMtypeidGetType(name));    pID = &(class_hash->table[hash % HASH_TABLE_SIZE]);    while (*pID) {        bucket = GET_BUCKET(class_hash, *pID);        if (name == bucket->name) {	    if (bucket->loadable)	        goto done;	    force_load = JNI_TRUE;	}	pID = &bucket->next;    }    if (force_load) {	/*	 * We found at least one matching named entry for a class that	 * was not known to be loadable through the defining class loader	 * of context->class. We must load our named class and update	 * the hash table in case one these entries matches our class.	 */	CVMClassBlock *cb = load_class_local(context, name);	int id = class_to_ID(context, cb, JNI_TRUE);	return id;    }    bucket = new_bucket(context, pID);    bucket->next = 0;    bucket->class = 0;    bucket->loadable = JNI_TRUE; /* name-only IDs are implicitly loadable */    bucket->name = name;done:    return *pID;}#ifdef CVM_TRACEstatic CVMClassTypeIDID_to_class_name(context_type *context, int ID){    hash_table_type *class_hash = &(context->class_hash);    hash_bucket_type *bucket = GET_BUCKET(class_hash, ID);    return bucket->name;}#endifstatic CVMClassBlock *ID_to_class(context_type *context, int ID){    hash_table_type *class_hash = &(context->class_hash);    hash_bucket_type *bucket = GET_BUCKET(class_hash, ID);    if (bucket->class == 0) {	CVMassert(bucket->loadable == JNI_TRUE);	bucket->class = load_class_global(context, bucket->name);    }    return bucket->class;}static fullinfo_type make_loadable_class_info(context_type *context, CVMClassBlock *cb){    return MAKE_FULLINFO(ITEM_Object, 0,			   class_to_ID(context, cb, JNI_TRUE));}static fullinfo_type make_class_info(context_type *context, CVMClassBlock *cb){    return MAKE_FULLINFO(ITEM_Object, 0,                         class_to_ID(context, cb, JNI_FALSE));}static fullinfo_typemake_class_info_from_name(context_type *context, CVMClassTypeID name){    return MAKE_FULLINFO(ITEM_Object, 0, class_name_to_ID(context, name));}/* * Called by CVMclassVerify.  Verify the code of each of the methods * in a class. */jbooleanVerifyClass(CVMExecEnv *ee, CVMClassBlock *cb, char *buffer, jint len){    context_type *context = (context_type *)malloc(sizeof(context_type));     jboolean result = JNI_TRUE;    int i;    if (context == NULL) {    	jio_snprintf(buffer, len, "(class: %C) Out Of Memory", cb);	return JNI_FALSE;    }    memset(context, 0, sizeof(context_type));    context->major_version = cb->major_version;    context->message = buffer;    context->message_buf_len = len;    context->ee = ee;    context->class = cb;    /* Set invalid method/field index of the context, in case anyone        calls CCerror */    context->mb = 0;#if 0 /* See comment in verify_field(). */    context->fb = 0;#endif    /* Don't call CCerror or anything that can call it above the setjmp! */

⌨️ 快捷键说明

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