bool Method::parse()

in vm/vmcore/src/class_support/Class_File_Loader.cpp [1759:2136]


bool Method::parse(Global_Env& env, Class* clss,
                   ByteReader &cfs, bool is_trusted_cl)
{
    if(!Class_Member::parse(clss, cfs))
        return false;
    //check method name
    if(is_trusted_cl && env.verify_all && !(_name == env.Init_String || _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 : " << _name->bytes);
                return false;
    } else {
        if(!(_name == env.Init_String || _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 : " << _name->bytes);
            return false;
        }
    }
    // check method descriptor
    if(!check_method_descriptor(_descriptor->bytes,
            clss->get_version() < JAVA5_CLASS_FILE_VERSION))
    {
        REPORT_FAILED_METHOD( " invalid descriptor");
        return false;
    }
    
    calculate_arguments_slot_num();

    //The total length of method parameters should be 255 or less.
    //See 4.4.3 in specification.
    if(_arguments_slot_num > 255) {
        REPORT_FAILED_METHOD("more than 255 arguments");
        return false;
    }
    // checked method descriptor

    _intf_method_for_fake_method = NULL;

    // set the has_finalizer, is_clinit and is_init flags
    if(_name == env.FinalizeName_String && _descriptor == env.VoidVoidDescriptor_String) {
        _flags.is_finalize = 1;
    }
    else if(_name == env.Init_String)
        _flags.is_init = 1;
    else if(_name == env.Clinit_String)
        _flags.is_clinit = 1;
    // check method access flags
    if(!is_clinit())
    {
        if(_class->is_interface())
        {
            if(!(is_abstract() && is_public())){
                REPORT_FAILED_CLASS_FORMAT(_class, " Interface method " 
                    << _name->bytes << _descriptor->bytes
                    << "must have both access flags ACC_ABSTRACT and ACC_PUBLIC set"
                    << "0x" << std::hex << _access_flags);
                return false;
            }
            if(_access_flags & ~(ACC_ABSTRACT | ACC_PUBLIC | ACC_VARARGS
                            | ACC_BRIDGE | ACC_SYNTHETIC)){
                REPORT_FAILED_CLASS_FORMAT(_class, " Interface method " 
                    << _name->bytes << _descriptor->bytes 
                    << " has invalid combination of access flags "
                    << "0x" << std::hex << _access_flags);
                return false;
            }
            //for class file version lower than 49 these three flags should be set to zero
            //See specification 4.6 Methods, for 1.4 Java.            
            if(_class->get_version() < JAVA5_CLASS_FILE_VERSION){
                _access_flags &= ~(ACC_BRIDGE | ACC_VARARGS | ACC_SYNTHETIC); 
            }
        } else {
            if(is_private() && is_protected()
                || is_private() && is_public()
                || is_protected() && is_public())
            {
                //See specification 4.7 Methods about access_flags
                REPORT_FAILED_CLASS_FORMAT(_class," Method "
                    << _name->bytes << _descriptor->bytes 
                    << " has invalid combination of access flags "
                    << "0x" << std::hex << _access_flags);
                return false;
            }
            if(is_abstract()
            && (is_final() || is_native() || is_private()
                    || is_static() || is_strict() || is_synchronized()))
            {
                bool bout = false;
                REPORT_FAILED_CLASS_FORMAT(_class, " Method " 
                    << _name->bytes << _descriptor->bytes
                    << " has invalid combination of access flags "
                    << "0x" << std::hex << _access_flags);
                return false;
            }
            if(is_init()) {
                if(_access_flags & ~(ACC_STRICT | ACC_VARARGS | ACC_SYNTHETIC
                        | ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED))
                {
                    REPORT_FAILED_CLASS_FORMAT(_class, " Method " 
                        << _name->bytes << _descriptor->bytes
                        << " has invalid combination of access flags "
                        << "0x" << std::hex << _access_flags);
                    return false;
                }    
            }
        }    
    } else {
        // Java VM specification
        // 4.7 Methods
        // "Class and interface initialization methods (3.9) are called
        // implicitly by the Java virtual machine; the value of their
        // access_flags item is ignored except for the settings of the
        // ACC_STRICT flag"
        _access_flags &= ACC_STRICT;
        // compiler assumes that <clinit> has ACC_STATIC
        // but VM specification does not require this flag to be present
        // so, enforce it
        _access_flags |= ACC_STATIC;
    }

    //check method attributes
    uint16 attr_count;
    if(!cfs.parse_u2_be(&attr_count)) {
        REPORT_FAILED_METHOD("truncated class file: failed to parse attributes count");
        return false;
    }

    unsigned numCode = 0;
    unsigned numExceptions = 0;
    unsigned numRuntimeVisibleAnnotations = 0;
    unsigned numRuntimeInvisibleAnnotations = 0;
    unsigned numRuntimeInvisibleParameterAnnotations = 0;
    U_32 attr_len = 0;
    ConstantPool& cp = clss->get_constant_pool();

    for (unsigned j=0; j<attr_count; j++) {
        Attributes cur_attr = parse_attribute(clss, cfs, method_attrs, &attr_len);
        switch(cur_attr) {
        case ATTR_Code:
            numCode++;
            if (numCode > 1) {
                REPORT_FAILED_METHOD(" there is more than one Code attribute");
                return false;
            }
            if(is_abstract() || is_native()) {
                REPORT_FAILED_CLASS_FORMAT(_class, " Method " << _name->bytes << _descriptor->bytes
                    << ": " << (is_abstract()?"abstract":(is_native()?"native":""))
                    << " should not have Code attribute present");
                return false;
            }
            if(!_parse_code(env, cp, attr_len, cfs))
                return false;
            break;

        case ATTR_Exceptions:
            numExceptions++;
            if(numExceptions > 1) {
                REPORT_FAILED_METHOD(" there is more than one Exceptions attribute");
                return false;
            }
            if(!_parse_exceptions(cp, attr_len, cfs))
                return false;
            break;

        case ATTR_RuntimeInvisibleParameterAnnotations:
            {
                //RuntimeInvisibleParameterAnnotations attribute is parsed only if
                //command line option -Xinvisible is set. See specification 4.8.17.
                if(env.retain_invisible_annotations) {
                    numRuntimeInvisibleParameterAnnotations++;
                    if(numRuntimeInvisibleParameterAnnotations > 1) {
                        REPORT_FAILED_CLASS_FORMAT(clss,
                            "more than one RuntimeInvisibleParameterAnnotations attribute");
                        return false;
                    }
                    if (!cfs.parse_u1(&_num_invisible_param_annotations)) {
                        REPORT_FAILED_CLASS_FORMAT(clss,
                            "truncated class file: failed to parse number of InvisibleParameterAnnotations");
                        return false;
                    }
                    U_32 read_len = 1;
                    if (_num_invisible_param_annotations) {
                        U_32 len =
                            parse_parameter_annotations(&_invisible_param_annotations,
                                        _num_invisible_param_annotations, cfs, _class);  
                        if(len == 0)
                            return false;
                        read_len += len;                        
                    }
                    if (attr_len != read_len) {
                        REPORT_FAILED_METHOD(
                            "error parsing InvisibleParameterAnnotations 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_RuntimeVisibleParameterAnnotations:
            {
                // See specification 4.8.16.
                if (_param_annotations) {
                    REPORT_FAILED_METHOD(
                        "more than one RuntimeVisibleParameterAnnotations attribute");
                    return false;
                }

                if (!cfs.parse_u1(&_num_param_annotations)) {
                    REPORT_FAILED_CLASS_FORMAT(clss,
                        "cannot parse number of ParameterAnnotations");
                    return false;
                }
                U_32 read_len = 1;
                if (_num_param_annotations) {
                    U_32 len = parse_parameter_annotations(&_param_annotations,
                                    _num_param_annotations, cfs, _class);
                    if(len == 0)
                        return false;
                    read_len += len;
                }
                if (attr_len != read_len) {
                    REPORT_FAILED_METHOD(
                        "error parsing ParameterAnnotations attribute"
                        << "; declared length " << attr_len
                        << " does not match actual " << read_len);
                    return false;
                }
            }
            break;

        case ATTR_AnnotationDefault:
            {
                //See specification 4.8.18 about default_value
                if (_default_value) {
                    REPORT_FAILED_METHOD("more than one AnnotationDefault attribute");
                    return false;
                }
                _default_value = (AnnotationValue *)_class->get_class_loader()->Alloc(
                    sizeof(AnnotationValue));
                //FIXME: verav should throw OOM
                U_32 read_len = parse_annotation_value(*_default_value, cfs, clss);
                if (read_len == 0) {
                    return false;
                } else if (read_len != attr_len) {
                    REPORT_FAILED_METHOD(
                        "declared length " << attr_len
                        << " of AnnotationDefault attribute "
                        << " does not match actual " << read_len);
                    return false;
                }
            }
            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 method_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 method_info structure may contain at most one RuntimeInvisibleAnnotations attribute.
                numRuntimeInvisibleAnnotations++; 
                if(numRuntimeInvisibleAnnotations > 1) {
                    REPORT_FAILED_CLASS_FORMAT(clss,
                        "more than one RuntimeInvisibleAnnotations attribute");
                    return false;
                }
                //RuntimeInvisibleAnnotations attribute is parsed only if
                //command line option -Xinvisible is set. See specification 4.8.15.
                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(clss,
                            "Truncated class file");
                        return false;
                    }
                }
            }
            break;

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

    if(!(is_abstract() || is_native()) && numCode == 0) {
        REPORT_FAILED_CLASS_FORMAT(_class, " Method " << _name->bytes << _descriptor->bytes
            << " should have Code attribute present");
        return false;
    }
    return true;
} //Method::parse