📄 classloader.c
字号:
typedef struct CICmallocs CICmallocs;struct CICcontext { unsigned char *ptr; unsigned char *end_ptr; ClassClass *cb; jmp_buf jump_buffer; char **detail; int pass; /* two passes, 1 or 2 */ int malloc_size; /* space needed for everything other than <clinit> */ int clinit_size; /* space needed for the <clinit> method */ int in_clinit; /* indicates whether we are loading <clinit> method */ struct { CICmallocs *mallocs; /* list of memory blocks used in the first pass */ void * alignment_padding; /* Whatever follows will be 8-byte aligned */ } pass1; struct { char *malloc_buffer; /* used to hold everything other than <clinit> */ char *malloc_ptr; /* current point of allocation */ char *clinit_buffer; /* used to hold the <clinit> method */ char *clinit_ptr; /* current point of allocation */ } pass2;};typedef struct CICcontext CICcontext;static char *getAsciz(CICcontext *, bool_t);static char *getAscizFromClass(CICcontext *, int i);static unsigned char get1byte(CICcontext *);static unsigned short get2bytes(CICcontext *);static unsigned long get4bytes(CICcontext *);static void getNbytes(CICcontext *, int count, char *buffer);static void *allocNBytes(CICcontext *, int size);static void freeBuffers(CICcontext *);static void LoadConstantPool(CICcontext *);static void ReadInCode(CICcontext *, struct methodblock *);static void ReadLineTable(CICcontext *, struct methodblock *mb);static void ReadExceptions(CICcontext *, struct methodblock *);static void ReadLocalVars(CICcontext *, struct methodblock *mb);static voidcreateInternalClass0(CICcontext *context, ClassClass *cb, struct Hjava_lang_ClassLoader *loader, char *name);bool_tcreateInternalClass1(unsigned char *ptr, unsigned char *end_ptr, ClassClass *cb, struct Hjava_lang_ClassLoader *loader, char *name, char **detail);/*========================================================================= * FUNCTION: createInternalClass * OVERVIEW: Invoked by LoadClassFromFile() or LoadClassFromZip() to * create an internal class. See createInternalClass1() for * details. * * INTERFACE: * parameters: unsigned char *: ptr * unsigned char *: end_ptr * ClassClass *: cb * struct Hjava_lang_ClassLoader *: loader * char *: name * char **: detail * * returns: bool_t *=======================================================================*/bool_tcreateInternalClass(unsigned char *ptr, unsigned char *end_ptr, ClassClass *cb, struct Hjava_lang_ClassLoader *loader, char *name, char **detail){ bool_t res; res = createInternalClass1(ptr, end_ptr, cb, loader, name, detail); return res;}/*========================================================================= * FUNCTION: JAVA_ERROR * OVERVIEW: Verifier error processing function. * * INTERFACE: * parameters: CICcontext *: context * char * : name * * returns: nothing *=======================================================================*/void JAVA_ERROR(CICcontext *context, char *name) { printCurrentClassName(); *(context->detail) = name; EE()->class_loading_msg = name; fprintf(stderr, "Class loading error: %s\n", name); exit(1);}/*========================================================================= * FUNCTION: createInternalClass1 * OVERVIEW: Auxiliary function for creating an internal class. * Invoked by createInternalClass(). * * Creates an internal class file from the indicated data. * It should be in a buffer for which the first byte is at * *ptr and the last byte is just before *end_ptr. * The class's classloader is indicated by the classloader * argument. * * We go through the buffer twice. In the first pass, we * determine the amount of storage needed by the class. * We then allocate a single chunk of memory, free the * temporary storage, and load from the buffer for the second * time. * * Since all storage needed by the class initialization method * <clinit> can be freed after the class is loaded, we count * the <clinit> space needs separately and store the <clinit> * method in a separate chunk of memory. * * INTERFACE: * parameters: unsigned char *: ptr * unsigned char *: end_ptr * ClassClass *: cb * struct Hjava_lang_ClassLoader *: loader * char *: name * char **: detail * * returns: bool_t *=======================================================================*/bool_tcreateInternalClass1(unsigned char *ptr, unsigned char *end_ptr, ClassClass *cb, struct Hjava_lang_ClassLoader *loader, char *name, char **detail){ struct CICcontext context_block; struct CICcontext *context = &context_block; /* Set up the context */ context->ptr = ptr; context->end_ptr = end_ptr; context->cb = cb; context->detail = detail; /* initialize the remaining fields of the context block */ context->pass = 0; context->malloc_size = 0; context->clinit_size = 0; context->in_clinit = 0; context->pass1.mallocs = 0; context->pass2.malloc_buffer = NULL; context->pass2.malloc_ptr = NULL; context->pass2.clinit_buffer = NULL; context->pass2.clinit_ptr = NULL; if (setjmp(context->jump_buffer)) { /* We've gotten an error of some sort * See comments below about zeroing these * two fields before freeing the temporary * buffer. */ cbConstantPool(cb) = NULL; cbFields(cb) = NULL; /* Zero out the method so that freeClass will * not try to free the clinit method. */ cbMethodsCount(cb) = 0; freeBuffers(context); return FALSE; } /* The first pass allows us to uncover any class format * errors and find out the size of the buffer needed. */ context->pass = 1; createInternalClass0(context, cb, loader, name); /* We must set the following two fields to zero before we free * the temporary buffers, because markClassClass may scan a * partially constructed class block in the second pass. * If these two fields are set to zero, markClassClass will * not scan the constant pool and field blocks, which may * point to freed memory. */ cbConstantPool(cb) = NULL; cbFields(cb) = NULL; /* Zero out the method so that freeClass will not try * to free the clinit method. */ cbMethodsCount(cb) = 0; freeBuffers(context); context->ptr = ptr; /* rewind the raw class data */ if (context->malloc_size > 0) { context->pass2.malloc_buffer = (char *)sysCalloc(1, context->malloc_size); if (context->pass2.malloc_buffer == 0) JAVA_ERROR(context, "out of memory"); } if (context->clinit_size > 0) { context->pass2.clinit_buffer = (char *)sysCalloc(1, context->clinit_size * sizeof(char)); if (context->pass2.clinit_buffer == 0) { sysFree(context->pass2.malloc_buffer); JAVA_ERROR(context, "out of memory"); } } context->pass2.malloc_ptr = context->pass2.malloc_buffer; context->pass2.clinit_ptr = context->pass2.clinit_buffer; /* The second pass accomplishes the real task. */ context->pass = 2; createInternalClass0(context, cb, loader, name); /* Valid class - let's put it in the class table. */ AddBinClass(cb); return TRUE;}/*========================================================================= * FUNCTION: createInternalClass0 * OVERVIEW: Auxiliary function invoked by createInternalClass1() during * the second pass to actually load the internal class file * structures such as the constant pool, method blocks, field * blocks and so on. * * INTERFACE: * parameters: CICcontext *: ptr * ClassClass *: cb * struct Hjava_lang_ClassLoader *: loader * char *: name * * returns: nothing *=======================================================================*/static voidcreateInternalClass0(CICcontext *context, ClassClass *cb, struct Hjava_lang_ClassLoader *loader, char *name){ int i, j, len; char buff[BUFSIZ]; char *UTFname = &buff[0]; union cp_item_type *constant_pool; unsigned char *type_table; int attribute_count; unsigned fields_count; struct methodblock *mb; struct fieldblock *fb; struct Classjava_lang_Class *ucb = unhand(cb); if (get4bytes(context) != JAVA_CLASSFILE_MAGIC) JAVA_ERROR(context, "Bad magic number"); ucb->minor_version = get2bytes(context); ucb->major_version = get2bytes(context); ucb->loader = loader; /* Ignore version # so that the preverifier can work with JDK 1.4 onwards */ /* if (ucb->major_version != JAVA_VERSION) JAVA_ERROR(context, "Bad major version number"); */ LoadConstantPool(context); constant_pool = ucb->constantpool; type_table = constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type; ucb->access = get2bytes(context) & ACC_WRITTEN_FLAGS; /* Get the name of the class */ i = get2bytes(context); /* index in constant pool of class */ ucb->name = getAscizFromClass(context, i); /* Conversion for Japanese filenames */ len = native2utf8(name, UTFname, BUFSIZ); if (name != NULL && strcmp(ucb->name, UTFname) != 0) JAVA_ERROR(context, "Wrong name"); constant_pool[i].clazz = cb; CONSTANT_POOL_TYPE_TABLE_SET_RESOLVED(type_table, i); if (loader) { /* We don't trust a classloader to do the right thing. . . */ ClassClass **pcb, **end_pcb; char *name = ucb->name; if (name == NULL || !IsLegalClassname(name, FALSE)) { JAVA_ERROR(context, "Bad name"); } BINCLASS_LOCK(); for (pcb = binclasses, end_pcb = pcb + nbinclasses; pcb < end_pcb; pcb++) { ClassClass *cb = *pcb; if ((cbLoader(cb) == loader) && (strcmp(name, cbName(cb)) == 0)) break; } BINCLASS_UNLOCK(); if (pcb < end_pcb) /* There's already a class with the same name and loader */ JAVA_ERROR(context, "Duplicate name"); } /* Get the super class name. */ i = get2bytes(context); /* index in constant pool of class */ if (i > 0) { ucb->super_name = getAscizFromClass(context, i); if (!IsLegalClassname(ucb->super_name, FALSE)) { JAVA_ERROR(context, "Bad superclass name"); } } i = ucb->implements_count = get2bytes(context); if (i > 0) { int j; ucb->implements = allocNBytes(context, i * sizeof(short)); for (j = 0; j < i; j++) { ucb->implements[j] = get2bytes(context); } } fields_count = ucb->fields_count = get2bytes(context); if (fields_count > 0) ucb->fields = (struct fieldblock *) allocNBytes(context, ucb->fields_count * sizeof(struct fieldblock)); for (i = fields_count, fb = ucb->fields; --i >= 0; fb++) { fieldclass(fb) = cb; fb->access = get2bytes(context) & ACC_WRITTEN_FLAGS; fb->name = getAsciz(context, FALSE); fb->signature = getAsciz(context, FALSE); attribute_count = get2bytes(context); for (j = 0; j < (int)attribute_count; j++) { char *attr_name = getAsciz(context, FALSE); int length = get4bytes(context); if (strcmp(attr_name, "ConstantValue") == 0) { if (fb->access & ACC_STATIC) { if (length != 2) { JAVA_ERROR(context, "Wrong size for VALUE attribute"); } fb->access |= ACC_VALKNOWN; /* we'll change this below */ fb->u.offset = get2bytes(context); } else { getNbytes(context, length, NULL); } } else if (strcmp(attr_name, "Deprecated") == 0) { if (length > 0) { JAVA_ERROR(context, "Bad deprecated size"); } fb->deprecated = TRUE; } else if (strcmp(attr_name, "Synthetic") == 0) { if (length > 0) { JAVA_ERROR(context, "Bad synthetic attribute size"); } fb->synthetic = TRUE; } else { getNbytes(context, length, NULL); } } /* if (fb->access & ACC_STATIC) { InitializeStaticVar(fb, context); } */ } if ((ucb->methods_count = get2bytes(context)) > 0) ucb->methods = (struct methodblock *) allocNBytes(context, ucb->methods_count * sizeof(struct methodblock)); for (i = cbMethodsCount(cb), mb = cbMethods(cb); --i >= 0; mb++) { fieldclass(&mb->fb) = cb; mb->fb.access = get2bytes(context) & ACC_WRITTEN_FLAGS; mb->fb.name = getAsciz(context, FALSE); mb->fb.signature = getAsciz(context, FALSE); if (strcmp(mb->fb.name, "<clinit>") == 0 && strcmp(mb->fb.signature, "()V") == 0) context->in_clinit = TRUE; mb->args_size = Signature2ArgsSize(mb->fb.signature) + ((mb->fb.access & ACC_STATIC) ? 0 : 1); if (mb->args_size > 255) JAVA_ERROR(context, "Too many arguments"); attribute_count = get2bytes(context); for (j = 0; j < attribute_count; j++) { char *attr_name = getAsciz(context, FALSE); if ((strcmp(attr_name, "Code") == 0) && ((mb->fb.access & (ACC_NATIVE | ACC_ABSTRACT))==0)) { ReadInCode(context, mb); } else if (strcmp(attr_name, "Exceptions") == 0) { ReadExceptions(context, mb); } else { int length = get4bytes(context); if (strcmp(attr_name, "Deprecated") == 0) { if (length > 0) { JAVA_ERROR(context, "Bad deprecated size"); } mb->fb.deprecated = TRUE; } else if (strcmp(attr_name, "Synthetic") == 0) { if (length > 0) { JAVA_ERROR(context, "Bad synthetic attribute size"); } mb->fb.synthetic = TRUE; } else { getNbytes(context, length, NULL); } } } context->in_clinit = FALSE; } /* See if there are class attributes */ attribute_count = get2bytes(context); for (j = 0; j < attribute_count; j++) { char *attr_name = getAsciz(context, FALSE); int length = get4bytes(context); if (strcmp(attr_name, "SourceFile") == 0) { if (length != 2) { JAVA_ERROR(context, "Wrong size for VALUE attribute"); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -