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