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