bool ConstantPool::check()

in vm/vmcore/src/class_support/Class_File_Loader.cpp [2503:2706]


bool ConstantPool::check(Global_Env* env, Class* clss, bool is_trusted_cl)
{
    for(unsigned i = 1; i < m_size; i++) {
        switch(unsigned char tag = get_tag(i))
        {
        case CONSTANT_Class:
        {
            unsigned name_index = get_class_name_index(i);
            if (!valid_cpi(clss, name_index, CONSTANT_Utf8, "for class name at CONSTANT_Class entry")) {
                // illegal name index
                return false;
            }
            if(!check_class_name(get_utf8_string(name_index)->bytes, get_utf8_string(name_index)->len,
                    clss->get_version() < JAVA5_CLASS_FILE_VERSION))
            {
                REPORT_FAILED_CLASS_FORMAT(clss," illegal CONSTANT_Class name "
                    << "\"" << get_utf8_string(name_index)->bytes << "\"");
                return false;
            }
            break;
        }
        case CONSTANT_Methodref:
        case CONSTANT_Fieldref:
        case CONSTANT_InterfaceMethodref:
        {
            unsigned class_index = get_ref_class_index(i);
            if (!valid_cpi(clss, class_index, CONSTANT_Class, "for class name at CONSTANT_*ref entry")) {
                return false;
            }
            unsigned name_type_index = get_ref_name_and_type_index(i);
            if (!valid_cpi(clss, name_type_index, CONSTANT_NameAndType, "for name-and-type at CONSTANT_*ref entry")) {
                return false;
            }            
            const char *next = NULL;
            String *name;
            String *descriptor;
            unsigned name_index = get_name_and_type_name_index(name_type_index);
            if(!valid_cpi(clss, name_index, CONSTANT_Utf8, "for name at CONSTANT_*ref entry")) {
                return false;
            }        
            unsigned descriptor_index = get_name_and_type_descriptor_index(name_type_index);
            if (!valid_cpi(clss, descriptor_index, CONSTANT_Utf8, "for descriptor at CONSTANT_*ref entry")) {
                return false;
            }

            name = get_utf8_string(name_index);
            descriptor = get_utf8_string(descriptor_index);

            if(tag == CONSTANT_Methodref)
            {
                //check method name
                if(is_trusted_cl) {
                    if(env->verify_all && (name != env->Init_String)
                        && !is_valid_member_name(name->bytes,name->len, clss->get_version() < JAVA5_CLASS_FILE_VERSION, true))
                    {
                        REPORT_FAILED_CLASS_FORMAT(clss, " illegal method name for CONSTANT_Methodref entry: " << name->bytes);
                        return false;
                    }
                    if(name->bytes[0] == '<' && name != env->Init_String) {
                        REPORT_FAILED_CLASS_FORMAT(clss, " illegal method name "<< name->bytes
                            << " at constant pool index " << name_index);
                        return false;
                    }
                } else { //always check method name if classloader is not system 
                    if((name != env->Init_String) 
                        && !is_valid_member_name(name->bytes,name->len, clss->get_version() < JAVA5_CLASS_FILE_VERSION, true))
                    {
                        REPORT_FAILED_CLASS_FORMAT(clss, " illegal method name for CONSTANT_Methodref entry: " 
                            << name->bytes);
                        return false;                    
                    }
                }
                //check method descriptor
                if(!check_method_descriptor(descriptor->bytes, clss->get_version() < JAVA5_CLASS_FILE_VERSION))
                {
                    REPORT_FAILED_CLASS_FORMAT(clss, " illegal method descriptor at CONSTANT_Methodref entry: "
                        << descriptor->bytes);
                    return false;
                }
                //for <init> method return type must be void
                //See specification 4.5.2
                if(name == env->Init_String)
                {
                    if(descriptor->bytes[descriptor->len - 1] != 'V')
                    {
                        REPORT_FAILED_CLASS_FORMAT(clss, " return type of <init> method"
                            " is not void at CONSTANT_Methodref entry");
                        return false;
                    }
                }
            }
            if(tag == CONSTANT_Fieldref)
            {
                //check field name
                if(is_trusted_cl) {
                    if(env->verify_all && !is_valid_member_name(name->bytes, name->len,
                                clss->get_version() < JAVA5_CLASS_FILE_VERSION, false))
                    {
                        REPORT_FAILED_CLASS_FORMAT(clss, " illegal field name for CONSTANT_Filedref entry: " 
                            << name->bytes);
                        return false;
                    }
                } else {
                    if(!is_valid_member_name(name->bytes, name->len,
                                clss->get_version() < JAVA5_CLASS_FILE_VERSION, false))
                    {
                        REPORT_FAILED_CLASS_FORMAT(clss, " illegal field name for CONSTANT_Filedref entry: " 
                            << name->bytes);
                        return false;                        
                    }            
                
                }
                //check field descriptor
                if(!is_valid_member_descriptor(descriptor->bytes, &next, false,
                        clss->get_version() < JAVA5_CLASS_FILE_VERSION) || *next != '\0' )
                {
                    REPORT_FAILED_CLASS_FORMAT(clss, " illegal field descriptor at CONSTANT_Fieldref entry: "
                        << descriptor->bytes);
                    return false;
                }
            }
            if(tag == CONSTANT_InterfaceMethodref)
            {
                //check method name, name can't be <init>
                //See specification 4.5.2 about name_and_type_index last sentence.
                if(is_trusted_cl) {
                    if(env->verify_all && (name != env->Clinit_String)
                                && !is_valid_member_name(name->bytes, name->len,
                                clss->get_version() < JAVA5_CLASS_FILE_VERSION, true))
                    {
                        REPORT_FAILED_CLASS_FORMAT(clss, " illegal method name for CONSTANT_InterfaceMethod entry: "
                            << name->bytes);
                        return false;
                    }
                } else {
                    if(!is_valid_member_name(name->bytes, name->len,
                                clss->get_version() < JAVA5_CLASS_FILE_VERSION, true))
                    {
                        REPORT_FAILED_CLASS_FORMAT(clss, " illegal method name for CONSTANT_InterfaceMethod entry: " 
                            << name->bytes);
                        return false;
                    }                    
                }
                //check method descriptor
                if(!check_method_descriptor(descriptor->bytes, clss->get_version() < JAVA5_CLASS_FILE_VERSION))
                {
                    REPORT_FAILED_CLASS_FORMAT(clss, " illegal method descriptor at CONSTANT_InterfaceMethodref entry: "
                        << descriptor->bytes);
                    return false;
                }
            }
            break;
        }
        case CONSTANT_String:
        {
            unsigned string_index = get_string_index(i);
            if (!valid_cpi(clss, string_index, CONSTANT_Utf8, "for string at CONSTANT_String entry")) {
                // illegal string index
                return false;
            }
            // set entry to the actual string
            resolve_entry(i, get_utf8_string(string_index));
            break;
        }
        case CONSTANT_Integer:
        case CONSTANT_Float:
            // not much to do here
            break;
        case CONSTANT_Long:
        case CONSTANT_Double:
            //check Long and Double indexes, n+1 index should be valid too.
            //See specification 4.5.5
            if(i + 1 == m_size){
                REPORT_FAILED_CLASS_FORMAT(clss, " illegal indexes for Long or Double " << i << " and " << i + 1);
                return false;
            }
            i++;
            break;
        case CONSTANT_NameAndType:
        {
            //See specification 4.5.6
            unsigned name_index = get_name_and_type_name_index(i);
            unsigned descriptor_index = get_name_and_type_descriptor_index(i);
            if(!valid_cpi(clss, name_index , CONSTANT_Utf8, "for name at CONSTANT_NameAndType entry")) {
                return false;
            }

            if (!valid_cpi(clss, descriptor_index, CONSTANT_Utf8, "for descriptor at CONSTANT_NameAndType entry")) {
                return false;
            }

            resolve_entry(i, get_utf8_string(name_index), get_utf8_string(descriptor_index));
            break;
        }
        case CONSTANT_Utf8:
            // nothing to do here
            break;
        default:
            REPORT_FAILED_CLASS_FORMAT(clss, " wrong constant pool tag " << get_tag(i));
            return false;
        }
    }
    return true;
} // ConstantPool::check