/* * Copyright 2002 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ /* This file was generated AUTOMATICALLY from a template file Wed Jun 17 10:43:47 PDT 1998 */ /*- * code for verifying the date in a ClassClass structure for internal * consistency. */ #include #include "oobj.h" #include "interpreter.h" #include "bool.h" #include "utf.h" #include "tree.h" #include "sys_api.h" extern bool_t verify_class_codes(ClassClass *cb); static bool_t verify_constant_pool(ClassClass *cb); static bool_t is_legal_fieldname(ClassClass *cb, char *name, int type); static bool_t is_legal_method_signature(ClassClass *cb, char *name, char *signature); static bool_t is_legal_field_signature(ClassClass *cb, char *name, char *signature); static char *skip_over_fieldname(char *name, bool_t slash_okay); static char *skip_over_field_signature(char *name, bool_t void_okay); static void CCerror (ClassClass *cb, char *format, ...); /* Argument for is_legal_fieldname */ enum { LegalClass, LegalField, LegalMethod }; bool_t VerifyClass(ClassClass *cb) { bool_t result = TRUE; struct methodblock *mb; struct fieldblock *fb; int i; if (CCIs(cb, Verified)) return TRUE; if (!verify_constant_pool(cb)) return FALSE; /* Make sure all the method names and signatures are okay */ for (i = cbMethodsCount(cb), mb = cbMethods(cb); --i >= 0; mb++) { char *name = mb->fb.name; char *signature = mb->fb.signature; if (! (is_legal_fieldname(cb, name, LegalMethod) && is_legal_method_signature(cb, name, signature))) result = FALSE; } /* Make sure all the field names and signatures are okay */ for (i = cbFieldsCount(cb), fb = cbFields(cb); --i >= 0; fb++) { if (! (is_legal_fieldname(cb, fb->name, LegalField) && is_legal_field_signature(cb, fb->name, fb->signature))) result = FALSE; } /* Make sure we are not overriding any final methods or classes*/ if (cbIsInterface(cb)) { struct methodblock *mb; if ((cbSuperclass(cb) == NULL) || (cbSuperclass(cb) != classJavaLangObject)) { CCerror(cb, "Interface %s has bad superclass", cbName(cb)); result = FALSE; } for (i = cbMethodsCount(cb), mb = cbMethods(cb); --i >= 0; mb++) { if (mb->fb.access & ACC_STATIC) { if (mb->fb.name[0] != '<') { /* Only internal methods can be static */ CCerror(cb, "Illegal static method %s in interface %s", mb->fb.name, cbName(cb)); result = FALSE; } } } } else if (cbSuperclass(cb)) { ClassClass *super_cb; unsigned bitvector_size = (unsigned)(cbMethodTableSize(cb) + 31) >> 5; long *bitvector = sysCalloc(bitvector_size, sizeof(long)); for (super_cb = cbSuperclass(cb); ; super_cb = cbSuperclass(super_cb)) { if (cbAccess(super_cb) & ACC_FINAL) { CCerror(cb, "Class %s is subclass of final class %s", cbName(cb), cbName(super_cb)); result = FALSE; } mb = cbMethods(super_cb); for (i = cbMethodsCount(super_cb); --i >= 0; mb++) { if (mb->fb.access & ACC_FINAL) { unsigned offset = mb->fb.u.offset; bitvector[offset >> 5] |= (1 << (offset & 0x1F)); } } if (cbSuperclass(super_cb) == NULL) break; } for (i = cbMethodsCount(cb), mb = cbMethods(cb); --i >= 0; mb++) { unsigned offset = mb->fb.u.offset; if ((offset > 0) && bitvector[offset >> 5] & (1 << (offset & 0x1F))) { CCerror(cb, "Class %s overrides final method %s.%s", cbName(cb), mb->fb.name, mb->fb.signature); result = FALSE; } } sysFree(bitvector); } else if (cb != classJavaLangObject) { CCerror(cb, "Class %s does not have superclass", cbName(cb)); result = FALSE; } if (result) result = verify_class_codes(cb); if (result) CCSet(cb, Verified); return result; } static bool_t verify_constant_pool(ClassClass *cb) { union cp_item_type *cp = cbConstantPool(cb); long cp_count = cbConstantPoolCount(cb); unsigned char *type_table; int i, type; const int utf8_resolved = (CONSTANT_Utf8 | CONSTANT_POOL_ENTRY_RESOLVED); if (cp_count == 0) /* Primitive classes */ return TRUE; type_table = cp[CONSTANT_POOL_TYPE_TABLE_INDEX].type; /* Let's make two quick passes over the constant pool. The first one * checks that everything is of the right type. */ for (i = 1; i < cp_count; i++) { switch(type = type_table[i]) { case CONSTANT_String: case CONSTANT_Class: { int index = cp[i].i; if ( (index < 1) || (index >= cp_count) || (type_table[index] != utf8_resolved)) { CCerror(cb, "Bad index in constant pool #%d", i); return FALSE; } break; } case CONSTANT_String | CONSTANT_POOL_ENTRY_RESOLVED: /* This can only happen if a string is the "initial" value of * some final static String. We assume that the checking has * already been done. */ break; case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: case CONSTANT_NameAndType: { unsigned index = (unsigned)(cp[i].i); int key1 = index >> 16; int key2 = index & 0xFFFF; if (key1 < 1 || key1 >= cp_count || key2 < 1 || key2 >= cp_count) { CCerror(cb, "Bad index in constant pool #%d", i); return FALSE; } if (type == CONSTANT_NameAndType) { if ( (type_table[key1] != utf8_resolved) || (type_table[key2] != utf8_resolved)) { CCerror(cb, "Bad index in constant pool."); return FALSE; } } else { if ( ((type_table[key1] & CONSTANT_POOL_ENTRY_TYPEMASK) != CONSTANT_Class) || ((type_table[key2] != CONSTANT_NameAndType))) { CCerror(cb, "Bad index in constant pool #%d", i); return FALSE; } } break; } case CONSTANT_Fieldref | CONSTANT_POOL_ENTRY_RESOLVED: case CONSTANT_Methodref | CONSTANT_POOL_ENTRY_RESOLVED: case CONSTANT_InterfaceMethodref | CONSTANT_POOL_ENTRY_RESOLVED: case CONSTANT_NameAndType | CONSTANT_POOL_ENTRY_RESOLVED: CCerror(cb, "Improperly resolved constant pool #%d", i); return FALSE; case CONSTANT_Class | CONSTANT_POOL_ENTRY_RESOLVED: case CONSTANT_Utf8 | CONSTANT_POOL_ENTRY_RESOLVED: case CONSTANT_Integer | CONSTANT_POOL_ENTRY_RESOLVED: case CONSTANT_Float | CONSTANT_POOL_ENTRY_RESOLVED: break; case CONSTANT_Long | CONSTANT_POOL_ENTRY_RESOLVED: case CONSTANT_Double | CONSTANT_POOL_ENTRY_RESOLVED: if ((i + 1 >= cp_count) || (type_table[i + 1] != CONSTANT_POOL_ENTRY_RESOLVED)) { CCerror(cb, "Improper constant pool long/double #%d", i); return FALSE; } else { i++; break; } case CONSTANT_Integer: case CONSTANT_Float: case CONSTANT_Long: case CONSTANT_Double: case CONSTANT_Utf8: CCerror(cb, "Improperly unresolved constant pool #%d", i); return FALSE; default: CCerror(cb, "Illegal constant pool type at #%d", i); return FALSE; } } for (i = 1; i < cp_count; i++) { switch(type = type_table[i]) { case CONSTANT_Class: { int index = cp[i].i; if (!is_legal_fieldname(cb, cp[index].cp, LegalClass)) return FALSE; break; } case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: { unsigned index = (unsigned)(cp[i].i); int name_type_index = index & 0xFFFF; int name_type_key = cp[name_type_index].i; int name_index = name_type_key >> 16; int signature_index = name_type_key & 0xFFFF; char *name = cp[name_index].cp; char *signature = cp[signature_index].cp; if (type == CONSTANT_Fieldref) { if (! (is_legal_fieldname(cb, name, LegalField) && is_legal_field_signature(cb, name, signature))) return FALSE; } else { if (! (is_legal_fieldname(cb, name, LegalMethod) && is_legal_method_signature(cb, name, signature))) return FALSE; } break; } } } return TRUE; } /* Return true if the entire second argument consists of a legal fieldname * (or classname, if the third argument is LegalClass). */ static bool_t is_legal_fieldname(ClassClass *cb, char *name, int type) { bool_t result; if (name[0] == '<') { result = (type == LegalMethod) && ((strcmp(name, "") == 0) || (strcmp(name, "") == 0)); } else { char *p; if (type == LegalClass && name[0] == SIGNATURE_ARRAY) { p = skip_over_field_signature(name, FALSE); } else { p = skip_over_fieldname(name, type == LegalClass); } result = (p != 0 && p[0] == '\0'); } if (!result) { char *thing = (type == LegalField) ? "Field" : (type == LegalMethod) ? "Method" : "Class"; CCerror(cb, "Illegal %s name \"%s\"", thing, name); return FALSE; } else { return TRUE; } } /* Return true if the entire string consists of a legal field signature */ static bool_t is_legal_field_signature(ClassClass *cb, char *fieldname, char *signature) { char *p = skip_over_field_signature(signature, FALSE); if (p != 0 && p[0] == '\0') { return TRUE; } else { CCerror(cb, "Field \"%s\" has illegal signature \"%s\"", fieldname, signature); return FALSE; } } static bool_t is_legal_method_signature(ClassClass *cb, char *methodname, char *signature) { char *p = signature; char *next_p; /* The first character must be a '(' */ if (*p++ == SIGNATURE_FUNC) { /* Skip over however many legal field signatures there are */ while ((next_p = skip_over_field_signature(p, FALSE)) != 0) p = next_p; /* The first non-signature thing better be a ')' */ if (*p++ == SIGNATURE_ENDFUNC) { if (methodname[0] == '<') { /* All internal methods must return void */ if ((p[0] == SIGNATURE_VOID) && (p[1] == '\0')) return TRUE; } else { /* Now, we better just have a return value. */ next_p = skip_over_field_signature(p, TRUE); if (next_p && next_p[0] == '\0') return TRUE; } } } CCerror(cb, "Method \"%s\" has illegal signature \"%s\"", methodname, signature); return FALSE; } $$Tables /* * This code mirrors Character.isJavaIdentifierStart. It determines whether * the specified character is a legal start of a Java identifier as per JLS. * * The parameter ch is the character to be tested; return 1 if the * character is a letter, 0 otherwise. */ #define isJavaIdentifierStart(ch) ($$Lookup(ch) & $$maskIsJavaIdentifierStart) /* * This code mirrors Character.isJavaIdentifierPart. It determines whether * the specified character is a legal part of a Java identifier as per JLS. * * The parameter ch is the character to be tested; return 1 if the * character is a digit, 0 otherwise. */ #define isJavaIdentifierPart(ch) ($$Lookup(ch) & $$maskIsJavaIdentifierPart) /* Take pointer to a string. Skip over the longest part of the string that * could be taken as a fieldname. Allow '/' if slash_okay is TRUE. * * Return a pointer to just past the fieldname. Return NULL if no fieldname * at all was found, or in the case of slash_okay being true, we saw * consecutive slashes (meaning we were looking for a qualified path but * found something that was badly-formed). */ static char * skip_over_fieldname(char *name, bool_t slash_okay) { bool_t first; char *p; unicode last_ch = 0; for (p = name, first = TRUE; ; first = FALSE) { char *old_p = p; unicode ch = next_utf2unicode(&p); if (isJavaIdentifierStart(ch) || (!first && isJavaIdentifierPart(ch)) || (slash_okay && ch == '/' && !first) || ch == '_' || ch == '$') { if (ch == '/' && last_ch == '/') { return 0; /* Don't permit consecutive slashes */ } else { last_ch = ch; } } else { return first ? 0 : old_p; } } } /* Take pointer to a string. Skip over the longest part of the string that * could be taken as a field signature. Allow "void" if void_okay. * * Return a pointer to just past the signature. Return NULL if no legal * signature is found. */ static char * skip_over_field_signature(char *name, bool_t void_okay) { for (;;) { switch (name[0]) { case SIGNATURE_VOID: if (!void_okay) return 0; /* FALL THROUGH */ case SIGNATURE_BOOLEAN: case SIGNATURE_BYTE: case SIGNATURE_CHAR: case SIGNATURE_SHORT: case SIGNATURE_INT: case SIGNATURE_FLOAT: case SIGNATURE_LONG: case SIGNATURE_DOUBLE: return name + 1; case SIGNATURE_CLASS: { /* Skip over the classname, if one is there. */ char *p = skip_over_fieldname(name + 1, TRUE); /* The next character better be a semicolon. */ if (p && p[0] == ';') return p + 1; return 0; } case SIGNATURE_ARRAY: /* The rest of what's there better be a legal signature. */ name++; void_okay = FALSE; break; default: return 0; } } } static void CCerror (ClassClass *cb, char *format, ...) { if (verbose) { va_list args; jio_fprintf(stderr, "VERIFIER CLASS ERROR %s:\n", cbName(cb)); va_start(args, format); jio_vfprintf(stderr, format, args); va_end(args); jio_fprintf(stderr, "\n"); } } /* For use from outside the file. Determine if the specified name is legal * UTF name for a classname. * * Note that this routine expects the internal form of qualified classes: * the dots should have been replaced by slashes. */ bool_t IsLegalClassname(char *name, bool_t allowArrayClass) { char *p; if (name[0] == SIGNATURE_ARRAY) { if (!allowArrayClass) { return FALSE; } else { /* Everything that's left better be a field signature */ p = skip_over_field_signature(name, FALSE); } } else { /* skip over the fieldname. Slashes are okay */ p = skip_over_fieldname(name, TRUE); } return (p != 0 && p[0] == '\0'); }