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