📄 check_code.c
字号:
* opc_getfield, opc_putfield, and opc_invokevirtual. * INTERFACE: * parameters: context_type *: context * int: instruction number * int: key * opcode_type: opcode * * returns: nothing *=======================================================================*/static void set_protected(context_type *context, int inumber, int key, opcode_type opcode) { fullinfo_type clazz_info = cp_index_to_class_fullinfo(context, key, TRUE); if (isSuperClass(context, clazz_info)) { char *name = cp_index_to_fieldname(context, key); char *signature = cp_index_to_signature(context, key); unsigned ID = NameAndTypeToHash(name, signature); ClassClass *calledClass = object_fullinfo_to_classclass(context, clazz_info); struct fieldblock *fb; if (ID == 0) { /* NameAndTypeToHash returns 0 if out of memory */ CCerror(context, "Out of memory"); return; } if (opcode != opc_invokevirtual && opcode != opc_invokespecial) { int n = cbFieldsCount(calledClass); fb = cbFields(calledClass); for (; --n >= 0; fb++) { if (fb->ID == ID) { goto haveIt; } } return; } else { struct methodblock *mb = cbMethods(calledClass); int n = cbMethodsCount(calledClass); for (; --n >= 0; mb++) { if (mb->fb.ID == ID) { fb = &mb->fb; goto haveIt; } } return; } haveIt: if (IsProtected(fb->access)) { if (IsPrivate(fb->access) || !IsSameClassPackage(calledClass, context->class)) context->instruction_data[inumber].protected = TRUE; } }}/*========================================================================= * FUNCTION: isSuperClass * OVERVIEW: Determines which of the classes are superclasses. * Returns true if the given clazz_info corresponds to a * a superclass. * INTERFACE: * parameters: context_type* : context * fullinfo_type: clazz_info * * returns: boolean type *=======================================================================*/static bool_t isSuperClass(context_type *context, fullinfo_type clazz_info) { fullinfo_type *fptr = context->superClasses; if (fptr == NULL) { ClassClass *cb; fullinfo_type *gptr; int i; /* Count the number of superclasses. By counting ourselves, and * not counting Object, we get the same number. */ for (i = 0, cb = context->class; cb != classJavaLangObject; i++, cb = cbSuperclass(cb)); /* Can't go on context heap since it survives more than one method */ context->superClasses = fptr = sysMalloc(sizeof(fullinfo_type)*(i + 1)); if (fptr == 0) { CCerror(context, "Out of memory"); } for (gptr = fptr, cb = context->class; cb != classJavaLangObject; ) { void **addr; cb = cbSuperclass(cb); *gptr++ = MAKE_CLASSNAME_INFO_WITH_COPY(context, cbName(cb), &addr); *addr = cb; } *gptr = 0; } for (; *fptr != 0; fptr++) { if (*fptr == clazz_info) return TRUE; } return FALSE;}/*========================================================================= * FUNCTION: initialize_exception_table * OVERVIEW: Initializes the exception table. * Looks through each item on the exception table and ensures * that each of the fields refers to a legal instruction. * INTERFACE: * parameters: pointer to the context_type structure. * * returns: nothing *=======================================================================*/static voidinitialize_exception_table(context_type *context){ struct methodblock *mb = context->mb; struct CatchFrame *exception_table = mb->exception_table; struct handler_info_type *handler_info = context->handler_info; short *code_data = context->code_data; unsigned long code_length = mb->code_length; int i; for (i = mb->exception_table_length; --i >= 0; exception_table++, handler_info++) { unsigned long start = exception_table->start_pc; unsigned long end = exception_table->end_pc; unsigned long handler = exception_table->handler_pc; unsigned catchType = exception_table->catchType; stack_item_type *stack_item = NEW(stack_item_type, 1); if (!( start < end && start >= 0 && isLegalTarget(context, start) && (end == code_length || isLegalTarget(context, end)))) { CCerror(context, "Illegal exception table range"); } if (!((handler > 0) && isLegalTarget(context, handler))) { CCerror(context, "Illegal exception table handler"); } handler_info->start = code_data[start]; /* end may point to one byte beyond the end of bytecodes. */ handler_info->end = (end == context->mb->code_length) ? context->instruction_count : code_data[end]; handler_info->handler = code_data[handler]; handler_info->stack_info.stack = stack_item; handler_info->stack_info.stack_size = 1; stack_item->next = NULL; if (catchType != 0) { union cp_item_type *cp = cbConstantPool(context->class); char *classname; verify_constant_pool_type(context, catchType, 1 << CONSTANT_Class); classname = GetClassConstantClassName(cp, catchType); stack_item->item = MAKE_CLASSNAME_INFO_WITH_COPY(context, classname, 0); } else { stack_item->item = context->throwable_info; } }}/*========================================================================= * FUNCTION: instruction_length * OVERVIEW: Given a pointer to an instruction, return its length. * Use the table opcode_length[] which is automatically built. * INTERFACE: * parameters: pointer to the instruction * * returns: int type *=======================================================================*/static int instruction_length(unsigned char *iptr){ int instruction = *iptr; switch (instruction) { case opc_tableswitch: { long *lpc = (long *) UCALIGN(iptr + 1); int index = ntohl(lpc[2]) - ntohl(lpc[1]); if ((index < 0) || (index > 65535)) { return -1; /* illegal */ } else { return (unsigned char *)(&lpc[index + 4]) - iptr; } } case opc_lookupswitch: { long *lpc = (long *) UCALIGN(iptr + 1); int npairs = ntohl(lpc[1]); if (npairs < 0 || npairs >= 8192) return -1; else return (unsigned char *)(&lpc[2 * (npairs + 1)]) - iptr; } case opc_wide: switch(iptr[1]) { case opc_ret: case opc_iload: case opc_istore: case opc_fload: case opc_fstore: case opc_aload: case opc_astore: case opc_lload: case opc_lstore: case opc_dload: case opc_dstore: return 4; case opc_iinc: return 6; default: return -1; } default: { /* A length of 0 indicates an error. */ int length = opcode_length[instruction]; return (length <= 0) ? -1 : length; } }}/*========================================================================= * FUNCTION: isLegalTarget * OVERVIEW: Given the target of a branch, make sure that it is a legal * target. Returns true if it is a legal target of a branch. * INTERFACE: * parameters: pointer to the context_type * int: offset * * returns: boolean type *=======================================================================*/static bool_t isLegalTarget(context_type *context, int offset){ struct methodblock *mb = context->mb; int code_length = mb->code_length; short *code_data = context->code_data; return (offset >= 0 && offset < code_length && code_data[offset] >= 0);}/*========================================================================= * FUNCTION: verify_constant_pool_type * OVERVIEW: Make sure that an element of the constant pool is really * of the indicated type. * INTERFACE: * parameters: pointer to the context_type * int: index * unsigned: mask * returns: nothing *=======================================================================*/static voidverify_constant_pool_type(context_type *context, int index, unsigned mask){ ClassClass *cb = context->class; union cp_item_type *constant_pool = cbConstantPool(cb); int nconstants = cbConstantPoolCount(cb); unsigned char *type_table = constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type; unsigned type; if ((index <= 0) || (index >= nconstants)) CCerror(context, "Illegal constant pool index"); type = CONSTANT_POOL_TYPE_TABLE_GET_TYPE(type_table, index); if ((mask & (1 << type)) == 0) CCerror(context, "Illegal type in constant pool");} /*========================================================================= * Functions for Data Flow Analysis *=======================================================================*//*========================================================================= * FUNCTION: initialize_dataflow * OVERVIEW: Initialize for data flow analysis. * INTERFACE: * parameters: pointer to the context_type * returns: nothing *=======================================================================*/static voidinitialize_dataflow(context_type *context) { instruction_data_type *idata = context->instruction_data; struct methodblock *mb = context->mb; fullinfo_type *reg_ptr; fullinfo_type full_info; char *p; /* Initialize the function entry, since we know everything about it. */ idata[0].stack_info.stack_size = 0; idata[0].stack_info.stack = NULL; idata[0].register_info.register_count = mb->args_size; idata[0].register_info.registers = NEW(fullinfo_type, mb->args_size); idata[0].register_info.mask_count = 0; idata[0].register_info.masks = NULL; idata[0].and_flags = 0; /* nothing needed */ idata[0].or_flags = FLAG_REACHED; /* instruction reached */ reg_ptr = idata[0].register_info.registers; if ((mb->fb.access & ACC_STATIC) == 0) { /* A non static method. If this is an <init> method, the first * argument is an uninitialized object. Otherwise it is an object of * the given class type. java.lang.Object.<init> is special since * we don't call its superclass <init> method. */ if (strcmp(mb->fb.name, "<init>") == 0 && context->currentclass_info != context->object_info) { *reg_ptr++ = MAKE_FULLINFO(ITEM_InitObject, 0, 0); idata[0].or_flags |= FLAG_NEED_CONSTRUCTOR; } else { *reg_ptr++ = context->currentclass_info; } } /* Fill in each of the arguments into the registers. */ for (p = mb->fb.signature + 1; *p != SIGNATURE_ENDFUNC; ) { char fieldchar = signature_to_fieldtype(context, &p, &full_info); if (no_floating_point && (fieldchar == 'D' || fieldchar == 'F')) { CCerror(context, "Floating point arguments not allowed"); } switch (fieldchar) { case 'D': case 'L': *reg_ptr++ = full_info; *reg_ptr++ = full_info + 1; break; default: *reg_ptr++ = full_info; break; } } p++; /* skip over right parenthesis */ if (*p == 'V') { context->return_type = MAKE_FULLINFO(ITEM_Void, 0, 0); } else { signature_to_fieldtype(context, &p, &full_info); context->return_type = full_info; } /* Indicate that we need to look at the first instruction. */ idata[0].changed = TRUE;} /*========================================================================= * FUNCTION: run_dataflow * OVERVIEW: Execute the data flow analysis as long as there are things * to change. * INTERFACE: * parameters: pointer to the context_type * returns: nothing *=======================================================================*/static voidrun_dataflow(context_type *context) { struct methodblock *mb = context->mb; int max_stack_size = mb->maxstack; instruction_data_type *idata = context->instruction_data; int icount = context->instruction_count; bool_t work_to_do = TRUE; int inumber; /* Run through the loop, until there is nothing left to do. */ while (work_to_do) { work_to_do = FALSE; for (inumber = 0; inumber < icount; inumber++) { instruction_data_type *this_idata = &idata[inumber]; if (this_idata->changed) { register_info_type new_register_info; stack_info_type new_stack_info; flag_type new_and_flags, new_or_flags; this_idata->changed = FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -