bool Field::parse()

in vm/vmcore/src/class_support/Class_File_Loader.cpp [718:1038]


bool Field::parse(Global_Env& env, Class *clss, ByteReader &cfs, bool is_trusted_cl)
{
    if(!Class_Member::parse(clss, cfs))
        return false;

    bool old_version = clss->get_version() < JAVA5_CLASS_FILE_VERSION;

    //check field name    
    if(is_trusted_cl) {
        if(env.verify_all
                && !is_valid_member_name(_name->bytes, _name->len, old_version, false))
        {
            REPORT_FAILED_CLASS_FORMAT(clss, "illegal field name : " << _name->bytes);
            return false;
        }
    } else {//always check field name if classloader is not trusted
        if(!is_valid_member_name(_name->bytes, _name->len, old_version, false))
        {
            REPORT_FAILED_CLASS_FORMAT(clss, "illegal field name : " << _name->bytes);
            return false;
        }
    }
    // check field descriptor
    //See specification 4.4.2 about field descriptors.
    const char* next;
    if(!is_valid_member_descriptor(_descriptor->bytes, &next, false, old_version)
            || *next != '\0') 
    {
        REPORT_FAILED_CLASS_FORMAT(clss, "illegal field descriptor : " << _descriptor->bytes);
        return false;
    }

    // check fields access flags
    //See specification 4.6 about access flags
    if(clss->is_interface()) {
        // check interface fields access flags
        if(!(is_public() && is_static() && is_final())){
            REPORT_FAILED_CLASS_FORMAT(clss, "interface field " << get_name()->bytes
                << " has invalid combination of access flags: "
                << "0x" << std::hex << _access_flags);
            return false;
        }
        if(_access_flags & ~(ACC_FINAL | ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC)){
            REPORT_FAILED_CLASS_FORMAT(clss, "interface field " << get_name()->bytes
                << " has invalid combination of access flags: "
                << "0x"<< std::hex << _access_flags);
            return false;
        }
        if(old_version) {
            //for class file version lower than 49 these two flags should be set to zero
            //See specification 4.5 Fields, for 1.4 Java.
            _access_flags &= ~(ACC_SYNTHETIC | ACC_ENUM);
        }
    } else if((is_public() && is_protected()
        || is_protected() && is_private()
        || is_public() && is_private())
        || (is_final() && is_volatile())) {
        REPORT_FAILED_CLASS_FORMAT(clss, "field " << get_name()->bytes
            << " has invalid combination of access flags: "
            << "0x" << std::hex << _access_flags);
        return false;
    }

    //check if field is magic type
     if (is_magic_type_name(_descriptor)) {
         _is_magic_type = 1;
     }

    //check field attributes
    uint16 attr_count;
    if(!cfs.parse_u2_be(&attr_count)) {
        REPORT_FAILED_CLASS_FORMAT(clss, "truncated class file: " 
            << "failed to parse attribute count for field " << get_name()->bytes);
        return false;
    }

    _offset_computed = 0;

    unsigned numConstantValue = 0;
    unsigned numRuntimeVisibleAnnotations = 0;
    unsigned numRuntimeInvisibleAnnotations = 0;
    U_32 attr_len = 0;

    ConstantPool& cp = clss->get_constant_pool();

    for (unsigned j=0; j<attr_count; j++)
    {
        // See specification 4.6 about attributes[]
        Attributes cur_attr = parse_attribute(clss, cfs, field_attrs, &attr_len);
        switch (cur_attr) {
        case ATTR_ConstantValue:
            {   // constant value attribute
                // a field can have at most 1 ConstantValue attribute
                // See specification 4.8.2 about ConstantValueAttribute.
                numConstantValue++;
                if (numConstantValue > 1) {
                    REPORT_FAILED_CLASS_FORMAT(clss, " field " <<
                        get_name()->bytes << " has more then one ConstantValue attribute");
                    return false;
                }
                // attribute length must be two (vm spec reference 4.7.3)
                if (attr_len != 2) {
                    REPORT_FAILED_CLASS_FORMAT(clss, " ConstantValue attribute has invalid length for field " 
                        << get_name()->bytes);
                    return false;
                }

                //For non-static field ConstantValue attribute must be silently ignored
                //See specification 4.8.2, second paragraph
                if(!is_static())
                {
                    if(!cfs.skip(attr_len))
                    {
                        REPORT_FAILED_CLASS_FORMAT(clss,
                            "Truncated class file");
                        return false;
                    }
                }
                else
                {
                    if(!cfs.parse_u2_be(&_const_value_index)) {
                        REPORT_FAILED_CLASS_FORMAT(clss, "truncated class file: failed to parse "
                            << "ConstantValue index for field " << get_name()->bytes);
                        return false;
                    }

                    if(!cp.is_valid_index(_const_value_index)) {
                        REPORT_FAILED_CLASS_FORMAT(clss, "invalid ConstantValue index for field " << get_name()->bytes);
                        return false;
                    }

                    Java_Type java_type = get_java_type();

                    switch(cp.get_tag(_const_value_index)) {
                    case CONSTANT_Long:
                        {
                            if (java_type != JAVA_TYPE_LONG) {
                                REPORT_FAILED_CLASS_FORMAT(clss, " data type CONSTANT_Long of ConstantValue " 
                                    << "does not correspond to the type of field " << get_name()->bytes);
                                return false;
                            }
                            const_value.l.lo_bytes = cp.get_8byte_low_word(_const_value_index);
                            const_value.l.hi_bytes = cp.get_8byte_high_word(_const_value_index);
                            break;
                        }
                    case CONSTANT_Float:
                        {
                            if (java_type != JAVA_TYPE_FLOAT) {
                                REPORT_FAILED_CLASS_FORMAT(clss, " data type CONSTANT_Float of ConstantValue "
                               	    << "does not correspond to the type of field " << get_name()->bytes);
                                return false;
                            }
                            const_value.f = cp.get_float(_const_value_index);
                            break;
                        }
                    case CONSTANT_Double:
                        {
                            if (java_type != JAVA_TYPE_DOUBLE) {
                                REPORT_FAILED_CLASS_FORMAT(clss, " data type CONSTANT_Double of ConstantValue "
                                    << "does not correspond to the type of field " << get_name()->bytes);
                                return false;
                            }
                            const_value.l.lo_bytes = cp.get_8byte_low_word(_const_value_index);
                            const_value.l.hi_bytes = cp.get_8byte_high_word(_const_value_index);
                            break;
                        }
                    case CONSTANT_Integer:
                        {
                            if ( !(java_type == JAVA_TYPE_INT         ||
                                java_type == JAVA_TYPE_SHORT       ||
                                java_type == JAVA_TYPE_BOOLEAN     ||
                                java_type == JAVA_TYPE_BYTE        ||
                                java_type == JAVA_TYPE_CHAR) )
                            {
                                REPORT_FAILED_CLASS_FORMAT(clss, " data type CONSTANT_Integer of ConstantValue "
                                    << "does not correspond to the type of field " << get_name()->bytes);
                                return false;
                            }
                            const_value.i = cp.get_int(_const_value_index);
                            break;
                        }
                    case CONSTANT_String:
                        {
                            if (java_type != JAVA_TYPE_CLASS) {
                                REPORT_FAILED_CLASS_FORMAT(clss, " data type CONSTANT_String of ConstantValue "
                                    << "does not correspond to the type of field " << get_name()->bytes);
                                return false;
                            }
                            const_value.string = cp.get_string(_const_value_index);
                            break;
                        }
                    case CONSTANT_UnusedEntry:
                        {
                            //do nothing here
                            break;
                        }
                    default:
                        {
                            REPORT_FAILED_CLASS_FORMAT(clss, " invalid data type tag of ConstantValue "
                                << "for field " << get_name()->bytes);
                            return false;
                        }
                    }//switch
                }//else for static field
            }//case ATTR_ConstantValue
            break;

        case ATTR_Synthetic:
            {
                if(attr_len != 0) {
                    REPORT_FAILED_CLASS_FORMAT(clss,
                        "attribute Synthetic has non-zero length");
                    return false;
                }
                _access_flags |= ACC_SYNTHETIC;
            }
            break;

        case ATTR_Deprecated:
            {
                if(attr_len != 0) {
                    REPORT_FAILED_CLASS_FORMAT(clss,
                        "attribute Deprecated has non-zero length");
                    return false;
                }
                _deprecated = true;
            }
            break;

        case ATTR_Signature:
            {
                if(_signature != NULL) {
                    REPORT_FAILED_CLASS_FORMAT(clss,
                        "more than one Signature attribute for the class");
                    return false;
                }
                if (!(_signature = parse_signature_attr(cfs, attr_len, clss))) {
                    return false;
                }
            }
            break;

        case ATTR_RuntimeVisibleAnnotations:
            {
                // Each field_info structure may contain at most one RuntimeVisibleAnnotations attribute.
                // See specification 4.8.14.
                numRuntimeVisibleAnnotations++;
                if(numRuntimeVisibleAnnotations > 1) {
                    REPORT_FAILED_CLASS_FORMAT(clss,
                        "more than one RuntimeVisibleAnnotations attribute");
                    return false;
                }

                U_32 read_len = parse_annotation_table(&_annotations, cfs, clss);
                if(read_len == 0)
                    return false;
                if (attr_len != read_len) {
                    REPORT_FAILED_CLASS_FORMAT(clss,
                        "error parsing Annotations attribute"
                        << "; declared length " << attr_len
                        << " does not match actual " << read_len);
                    return false;
                }
            }
            break;

        case ATTR_RuntimeInvisibleAnnotations:
            {
                // Each field_info structure may contain at most one RuntimeInvisibleAnnotations attribute.
                numRuntimeInvisibleAnnotations++;
                if(numRuntimeInvisibleAnnotations > 1) {
                    REPORT_FAILED_CLASS_FORMAT(clss,
                        "more than one RuntimeVisibleAnnotations attribute");
                    return false;
                }
                if(env.retain_invisible_annotations) {
                    U_32 read_len =
                        parse_annotation_table(&_invisible_annotations, cfs, clss);
                    if(read_len == 0)
                        return false;
                    if(attr_len != read_len) {
                        REPORT_FAILED_CLASS_FORMAT(clss,
                            "error parsing RuntimeInvisibleAnnotations attribute"
                            << "; declared length " << attr_len
                            << " does not match actual " << read_len);
                        return false;
                    }
                } else {
                    if(!cfs.skip(attr_len)) {
                        REPORT_FAILED_CLASS_FORMAT(_class,
                            "Truncated class file");
                        return false;
                    }
                }
            }
            break;

        case ATTR_UNDEF:
            // unrecognized attribute; skipped
            break;
        case ATTR_ERROR:
            return false;
        default:
            REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/InternalError",
                _class->get_name()->bytes << ": unknown error occured "
                "while parsing attributes for field "
                << _name->bytes << _descriptor->bytes
                << "; unprocessed attribute " << cur_attr);
            return false;
        } // switch
    } // for

    TypeDesc* td = type_desc_create_from_java_descriptor(get_descriptor()->bytes, clss->get_class_loader());
    if( td == NULL ) {
        exn_raise_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError);
        return false;
    }
    set_field_type_desc(td);

    return true;
} //Field::parse