| /* |
| * Copyright (c) 2002, 2008, Oracle and/or its affiliates. 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. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.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 <ctype.h> |
| |
| #include "oobj.h" |
| #include "interpreter.h" |
| #include "bool.h" |
| #include "utf.h" |
| #include "tree.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, "<init>") == 0) || |
| (strcmp(name, "<clinit>") == 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'); |
| } |