Index: vm/vmcore/include/annotations.h
===================================================================
--- vm/vmcore/include/annotations.h (revision 490148)
+++ vm/vmcore/include/annotations.h (working copy)
@@ -29,10 +29,11 @@
struct Annotation;
struct AnnotationValue;
-// Returns array of declared annotations.
+// Returns array of declared visible annotations
+// and in case -Xinvisible command line flag is set also returns array of invisible annotations.
// Returns zero-sized array if there are no annotations.
// May raise an exception, in this case returns null.
-jobjectArray get_annotations(JNIEnv* jenv, AnnotationTable* table, Class* clss);
+jobjectArray get_annotations(JNIEnv* jenv, AnnotationTable* table, AnnotationTable *inv_table, Class* clss);
// Returns resolved annotation or null if resolution failed.
// If the cause parameter is not null, resolution error is assigned to it for upstream processing;
Index: vm/vmcore/include/class_member.h
===================================================================
--- vm/vmcore/include/class_member.h (revision 490148)
+++ vm/vmcore/include/class_member.h (working copy)
@@ -86,6 +86,9 @@
String *get_signature() const {return _signature;}
AnnotationTable* get_declared_annotations() const {return _annotations;}
+ AnnotationTable* get_declared_invisible_annotations() const {
+ return _invisible_annotations;
+ }
friend void assign_offsets_to_class_fields(Class *);
friend void add_new_fake_method(Class *clss, Class *example, unsigned *next);
@@ -109,6 +112,7 @@
#endif
_synthetic = _deprecated = false;
_annotations = NULL;
+ _invisible_annotations = NULL;
_signature = NULL;
}
@@ -122,6 +126,7 @@
bool _synthetic;
bool _deprecated;
AnnotationTable* _annotations;
+ AnnotationTable* _invisible_annotations;
uint16 _access_flags;
String* _name;
@@ -208,7 +213,7 @@
unsigned is_transient() {return (_access_flags&ACC_TRANSIENT);}
bool is_enum() {return (_access_flags&ACC_ENUM)?true:false;}
- bool parse(Class* clss, ByteReader& cfs);
+ bool parse(Global_Env& env, Class* clss, ByteReader& cfs);
unsigned calculate_size();
@@ -647,11 +652,22 @@
AnnotationTable * get_param_annotations(unsigned index) {
return index < _num_param_annotations ? _param_annotations[index] : NULL;
}
+ unsigned get_num_invisible_param_annotations() {
+ return _num_invisible_param_annotations;
+ }
+ AnnotationTable * get_invisible_param_annotations(unsigned index) {
+ return index < _num_invisible_param_annotations ?
+ _invisible_param_annotations[index] : NULL;
+ }
+
AnnotationValue * get_default_value() {return _default_value; }
private:
uint8 _num_param_annotations;
AnnotationTable ** _param_annotations;
+ uint8 _num_invisible_param_annotations;
+ AnnotationTable ** _invisible_param_annotations;
+
AnnotationValue * _default_value;
unsigned _index; // index in method table
Index: vm/vmcore/include/environment.h
===================================================================
--- vm/vmcore/include/environment.h (revision 490148)
+++ vm/vmcore/include/environment.h (working copy)
@@ -74,7 +74,8 @@
size_t system_page_size; // system page size according to use_large_pages value
bool verify_all; // psrebriy 20050815 Verify all classes including loaded by bootstrap class loader
bool pin_interned_strings; // if true, interned strings are never moved
-
+ bool retain_invisible_annotations; // retain InvisibleAnnotation and InvisibleParameterAnnotation
+
Lock_Manager *p_jit_a_method_lock;
Lock_Manager *p_vtable_patch_lock;
Lock_Manager *p_meth_addr_table_lock;
Index: vm/vmcore/include/Class.h
===================================================================
--- vm/vmcore/include/Class.h (revision 490148)
+++ vm/vmcore/include/Class.h (working copy)
@@ -161,7 +161,7 @@
enum ConstPoolTags {
/** pointer to the tags array.*/
CONSTANT_Tags = 0,
- /** The rest of tag values are taken from
+ /** The next 11 tag values are taken from
*
* The Java Virtual Machine Specification, Chapter 4, The Constant
* Pool section.*/
@@ -176,6 +176,9 @@
CONSTANT_Methodref = 10,
CONSTANT_InterfaceMethodref = 11,
CONSTANT_NameAndType = 12,
+ CONSTANT_Last = CONSTANT_NameAndType,
+ /** used to mark second entry of Long and Double*/
+ CONSTANT_UnusedEntry = CONSTANT_Last + 1,
};
@@ -1001,6 +1004,9 @@
// annotations for this class
AnnotationTable* m_annotations;
+ //invisible annotations for this class
+ AnnotationTable* m_invisible_annotations;
+
// thread, which currently executes
VM_thread* m_initializing_thread;
@@ -1340,7 +1346,11 @@
/** Gets a collection of annotations.
* @return A collection of annotations.*/
AnnotationTable* get_annotations() const { return m_annotations; }
-
+ /** Gets a collection of invisible annotations.
+ * @return A collection of invisible annotations.*/
+ AnnotationTable* get_invisible_annotations() const {
+ return m_invisible_annotations;
+ }
/** Gets a class instance size.
* @return A size of the allocated instance in bytes.*/
unsigned int get_allocated_size() const { return m_allocated_size; }
Index: vm/vmcore/src/reflection/annotations.cpp
===================================================================
--- vm/vmcore/src/reflection/annotations.cpp (revision 490148)
+++ vm/vmcore/src/reflection/annotations.cpp (working copy)
@@ -36,10 +36,15 @@
#include "primitives_support.h"
#include "vm_log.h"
-jobjectArray get_annotations(JNIEnv* jenv, AnnotationTable* table, Class* clss)
+jobjectArray get_annotations(JNIEnv* jenv, AnnotationTable* table, AnnotationTable* inv_table, Class* clss)
{
- unsigned num = table ? table->length : 0;
- TRACE("annotations table size = " << num);
+ unsigned table_num = table ? table->length : 0;
+ TRACE("annotations table size = " << table_num);
+
+ unsigned inv_table_num = inv_table ? inv_table->length : 0;
+ TRACE("invisible annotations table size = " << inv_table_num);
+
+ unsigned num = table_num + inv_table_num;
static Class* antn_class = jni_get_vm_env(jenv)->LoadCoreClass(
"java/lang/annotation/Annotation");
@@ -52,7 +57,8 @@
return NULL;
}
- for (unsigned i = 0; i < num; ++i) {
+ unsigned i;
+ for (i = 0; i < table_num; ++i) {
jobject element = resolve_annotation(jenv, table->table[i], clss);
if (!element) {
assert(exn_raised());
@@ -62,7 +68,16 @@
assert(!exn_raised());
}
}
-
+ for (i = table_num; i < num; ++i) {
+ jobject element = resolve_annotation(jenv, inv_table->table[i - table_num], clss);
+ if (!element) {
+ assert(exn_raised());
+ return NULL;
+ } else {
+ SetObjectArrayElement(jenv, array, i, element);
+ assert(!exn_raised());
+ }
+ }
return array;
}
Index: vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMGenericsAndAnnotations.cpp
===================================================================
--- vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMGenericsAndAnnotations.cpp (revision 490148)
+++ vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMGenericsAndAnnotations.cpp (working copy)
@@ -62,7 +62,9 @@
{
Class_Member* member = (Class_Member*) ((POINTER_SIZE_INT) jmember);
TRACE("Requested annotations for member " << member);
- return get_annotations(jenv, member->get_declared_annotations(), member->get_class());
+ return get_annotations(jenv, member->get_declared_annotations(),
+ member->get_declared_invisible_annotations(),
+ member->get_class());
}
JNIEXPORT jobjectArray JNICALL Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getDeclaredAnnotations__Ljava_lang_Class_2
@@ -70,7 +72,8 @@
{
Class* clazz = jclass_to_struct_Class(jclazz);
TRACE("Requested annotations for class " << clazz);
- return get_annotations(jenv, clazz->get_annotations(), clazz);
+ return get_annotations(jenv, clazz->get_annotations(),
+ clazz->get_invisible_annotations(), clazz);
}
JNIEXPORT jobjectArray JNICALL Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getParameterAnnotations
@@ -83,7 +86,8 @@
static Class* array_class = genv->LoadCoreClass(
"[Ljava/lang/annotation/Annotation;");
- unsigned num = method->get_num_param_annotations();
+ unsigned param_num = method->get_num_param_annotations();
+ unsigned num = param_num + method->get_num_invisible_param_annotations();
TRACE("Requested parameters annotations for method " << method
<< "; num=" << num);
@@ -113,8 +117,11 @@
return NULL;
}
- for (unsigned i = 0; i < num; ++i) {
- jobject element = get_annotations(jenv, method->get_param_annotations(i), declaring_class);
+ unsigned i;
+ for (i = 0; i < param_num; ++i) {
+ jobject element = get_annotations(jenv,
+ method->get_param_annotations(i),
+ NULL, declaring_class);
if (!element) {
assert(exn_raised());
return NULL;
@@ -123,7 +130,19 @@
assert(!exn_raised());
}
}
-
+ for (i = param_num; i < num; ++i) {
+ jobject element = get_annotations(jenv, NULL,
+ method->get_invisible_param_annotations(i - param_num),
+ declaring_class);
+ if (!element) {
+ assert(exn_raised());
+ return NULL;
+ } else {
+ SetObjectArrayElement(jenv, array, i, element);
+ assert(!exn_raised());
+ }
+ }
+
return array;
}
Index: vm/vmcore/src/class_support/C_Interface.cpp
===================================================================
--- vm/vmcore/src/class_support/C_Interface.cpp (revision 490148)
+++ vm/vmcore/src/class_support/C_Interface.cpp (working copy)
@@ -843,6 +843,14 @@
case CONSTANT_Class:
jt = JAVA_TYPE_CLASS;
break;
+ case CONSTANT_UnusedEntry:
+ if(cp.get_tag(index - 1) == CONSTANT_Double) {
+ jt = JAVA_TYPE_DOUBLE;
+ break;
+ } else if(cp.get_tag(index - 1) == CONSTANT_Long) {
+ jt = JAVA_TYPE_LONG;
+ break;
+ }
default:
DIE("non-constant type is requested from constant pool : " << cp.get_tag(index));
}
Index: vm/vmcore/src/class_support/Environment.cpp
===================================================================
--- vm/vmcore/src/class_support/Environment.cpp (revision 490148)
+++ vm/vmcore/src/class_support/Environment.cpp (working copy)
@@ -136,6 +136,7 @@
verify_all = false;
pin_interned_strings = false;
+ retain_invisible_annotations = false;
// initialize critical sections
p_jit_a_method_lock = new Lock_Manager();
Index: vm/vmcore/src/class_support/Class.cpp
===================================================================
--- vm/vmcore/src/class_support/Class.cpp (revision 490148)
+++ vm/vmcore/src/class_support/Class.cpp (working copy)
@@ -627,7 +627,9 @@
_line_number_table = NULL;
_local_vars_table = NULL;
_num_param_annotations = 0;
+ _num_invisible_param_annotations = 0;
_param_annotations = NULL;
+ _invisible_param_annotations = NULL;
_default_value = NULL;
pending_breakpoints = 0;
Index: vm/vmcore/src/class_support/Resolve.cpp
===================================================================
--- vm/vmcore/src/class_support/Resolve.cpp (revision 490148)
+++ vm/vmcore/src/class_support/Resolve.cpp (working copy)
@@ -1048,6 +1048,7 @@
return true;
case CONSTANT_Double: // fall through
case CONSTANT_Long:
+ case CONSTANT_UnusedEntry:
return true;
}
return false;
Index: vm/vmcore/src/class_support/Class_File_Loader.cpp
===================================================================
--- vm/vmcore/src/class_support/Class_File_Loader.cpp (revision 490148)
+++ vm/vmcore/src/class_support/Class_File_Loader.cpp (working copy)
@@ -48,16 +48,14 @@
//
// TODO list:
-//
-// (1) verify correctness of Method access_flags for different class file versions
-// (2) verify correctness of Field access_flags for different class file versions
-// (3) verify Class access_flags for different class file versions
-// (4) check that Signature of attribute LocalVariableTypeTable of Code attribute is valid
-// (5) implement functionality of RuntimeInvisibleAnnotations
-// and RuntimeInvisibleParameterAnnotations, not just skip them
-// (6) check Signature attribute, not only parse it
-//
+// (1) Make macro valid_cpi function static bool, add ClassFormatError reporting to valid_cpi,
+// replace functions is_valid_index and is_ by valid_cpi.
+// (2) Funtion parse_annotation_value doesn't report ClassFormatError in case
+// const_inx is invalid.
+// (3) Implement field and method name check for 45 and lower versions of class file.
+//
+
#define REPORT_FAILED_CLASS_FORMAT(klass, msg) \
{ \
std::stringstream ss; \
@@ -69,8 +67,6 @@
(clss->get_constant_pool().is_valid_index(idx) \
&& clss->get_constant_pool().get_tag(idx) == type)
-
-
static String* cp_check_utf8(ConstantPool& cp, unsigned utf8_index)
{
if(!cp.is_valid_index(utf8_index) || !cp.is_utf8(utf8_index)) {
@@ -542,13 +538,30 @@
return read_len;
}
+static uint32 parse_parameter_annotations(AnnotationTable *** table,
+ uint8 num_annotations,
+ ByteReader& cfs, Class* clss)
+{
+ *table = (AnnotationTable**)clss->get_class_loader()->Alloc(
+ num_annotations * sizeof (AnnotationTable*));
+ //FIXME: verav should throw OOM
+ uint32 len = 0;
+ for (unsigned i = 0; i < num_annotations; i++)
+ {
+ uint32 next_len = parse_annotation_table(*table + i, cfs, clss);
+ if(next_len == 0)
+ return 0;
+ len += next_len;
+ }
+ return len;
+}
+
void* Class_Member::Alloc(size_t size) {
ClassLoader* cl = get_class()->get_class_loader();
assert(cl);
return cl->Alloc(size);
}
-
bool Class_Member::parse(Class* clss, ByteReader &cfs)
{
if (!cfs.parse_u2_be(&_access_flags)) {
@@ -596,7 +609,7 @@
// further constrained so that, with the exception of the special method names (§3.9)
// and , they must not contain the characters ’<’ or ’>’.
static inline bool
-check_field_name(const char *name, unsigned len)
+check_field_name(const char *name, unsigned len, bool old_version)
{
for (unsigned i = 0; i < len; i++) {
switch(name[i]){
@@ -611,7 +624,7 @@
}
static inline bool
-check_method_name(const char *name, unsigned len)
+check_method_name(const char *name, unsigned len, bool version)
{
for (unsigned i = 0; i < len; i++) {
switch(name[i]){
@@ -666,7 +679,7 @@
return false;
}
if(*iterator == '/') {
- if(!check_field_name(descriptor, id_len))
+ if(!check_field_name(descriptor, id_len, false))
return false;
id_len = 0;
descriptor = iterator + 1;
@@ -674,7 +687,7 @@
id_len++;
}
}
- if(!check_field_name(descriptor, id_len))
+ if(!check_field_name(descriptor, id_len, false))
return false;
*next = iterator + 1;
return true;
@@ -696,16 +709,21 @@
// DIE( "unreachable code!" ); // exclude remark #111: statement is unreachable
}
-bool Field::parse(Class *clss, ByteReader &cfs)
+//checks of field and method name depend on class version
+static const uint16 JAVA5_CLASS_FILE_VERSION = 49;
+
+bool Field::parse(Global_Env& env, Class *clss, ByteReader &cfs )
{
if(!Class_Member::parse(clss, cfs))
return false;
- if(!check_field_name(_name->bytes, _name->len)) {
+ if(env.verify_all
+ && !check_field_name(_name->bytes, _name->len,
+ clss->get_version() < JAVA5_CLASS_FILE_VERSION))
+ {
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;
@@ -716,24 +734,32 @@
// check fields access flags
//See specification 4.6 about access flags
- if( clss->is_interface() ) {
+ 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
- << " does not have one of ACC_PUBLIC, ACC_STATIC, or ACC_FINAL access flags set");
+ << " 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 illegal access flags set : " << _access_flags); //FIXME to literal form
+ << " has invalid combination of access flags: "
+ << "0x"<< std::hex << _access_flags);
return false;
}
+ if(clss->get_version() < JAVA5_CLASS_FILE_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 : " << _access_flags); //FIXME to literal form
+ << " has invalid combination of access flags: "
+ << "0x" << std::hex << _access_flags);
return false;
}
@@ -875,6 +901,11 @@
const_value.string = cp.get_string(_const_value_index);
break;
}
+ case CONSTANT_UnusedEntry:
+ {
+ //do nothing here
+ break;
+ }
default:
{
REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss,
@@ -935,6 +966,8 @@
}
uint32 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"
@@ -947,15 +980,30 @@
case ATTR_RuntimeInvisibleAnnotations:
{
+ // Each field_info structure may contain at most one RuntimeInvisibleAnnotations attribute.
if(++numRuntimeInvisibleAnnotations > 1) {
REPORT_FAILED_CLASS_FORMAT(clss,
"more than one RuntimeVisibleAnnotations attribute");
return false;
}
- if(!cfs.skip(attr_len)) {
- REPORT_FAILED_CLASS_FORMAT(clss,
- "failed to skip RuntimeInvisibleAnnotations attribute");
- return false;
+ if(env.retain_invisible_annotations) {
+ uint32 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,
+ "failed to skip RuntimeInvisibleAnnotations attribute");
+ return false;
+ }
}
}
break;
@@ -1217,7 +1265,8 @@
return false;
}
- if(!check_field_name(name->bytes, name->len))
+ if(!check_field_name(name->bytes, name->len,
+ _class->get_version() < JAVA5_CLASS_FILE_VERSION))
{
REPORT_FAILED_METHOD("name of local variable: " << name->bytes <<
" in " << attr_name << " attribute is not stored as unqualified name");
@@ -1247,10 +1296,18 @@
"in " << attr_name << " attribute");
return false;
}
+ //See specification about index value 4.8.11 and 4.8.12
+ if((descriptor->bytes[0] == 'D' || descriptor->bytes[0] == 'J')
+ && index >= _max_locals - 1)
+ {
+ REPORT_FAILED_METHOD("invalid local index "
+ << index << " in " << attr_name << " attribute");
+ return false;
+ }
if (index >= _max_locals) {
REPORT_FAILED_METHOD("invalid local index "
- "in " << attr_name << " attribute");
+ << index << " in " << attr_name << " attribute");
return false;
}
@@ -1274,8 +1331,8 @@
&&table->table[j].length == table->table[i].length
&&table->table[j].index == table->table[i].index)
{
- REPORT_FAILED_METHOD("Duplicate attribute "<< attr_name
- <<" for local variable ");
+ REPORT_FAILED_METHOD("Duplicate local variable "<< table->table[j].name
+ << " in attribute " << attr_name);
return false;
}
}
@@ -1328,9 +1385,9 @@
|| (_byte_code_length >= (1<<16)))
{
REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
- _class->get_name()->bytes << ": bytecode length for method "
- << _name->bytes << _descriptor->bytes
- << " has zero or exceeding length");
+ _class->get_name()->bytes << ": invalid bytecode length "
+ << _byte_code_length << " for method "
+ << _name->bytes << _descriptor->bytes);
return false;
}
@@ -1648,10 +1705,11 @@
{
if(!Class_Member::parse(clss, cfs))
return false;
-
- if(!(_name == env.Init_String || _name == env.Clinit_String))
+ //check name only if flag verify_all is set from command line
+ if(env.verify_all && !(_name == env.Init_String || _name == env.Clinit_String))
{
- if(!check_method_name(_name->bytes, _name->len))
+ if(!check_method_name(_name->bytes, _name->len,
+ clss->get_version() < JAVA5_CLASS_FILE_VERSION))
{
REPORT_FAILED_CLASS_FORMAT(clss, "illegal method name : " << _name->bytes);
return false;
@@ -1673,8 +1731,8 @@
if(_arguments_slot_num > 255) {
REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
_class->get_name()->bytes <<
- ": method has more than 255 arguments "
- << _name->bytes );
+ ": method " << _name->bytes << _descriptor->bytes
+ << " has more than 255 arguments " );
return false;
}
// checked method descriptor
@@ -1692,61 +1750,68 @@
// check method access flags
if(!is_clinit())
{
- if(is_private() && is_protected() || is_private() && is_public() || is_protected() && is_public())
- {
- bool bout = false;
- //See specification 4.7 Methods about access_flags
- REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
- _class->get_name()->bytes << ": invalid combination of access flags ("
- << ((bout = is_public())?"ACC_PUBLIC":"")
- << (bout?"|":"")
- << ((bout |= is_protected())?"ACC_PROTECTED":"")
- << (bout?"|":"")
- << (is_private()?"ACC_PRIVATE":"")
- << ") for method "
- << _name->bytes << _descriptor->bytes);
- return false;
- }
- if(is_abstract()
- && (is_final() || is_native() || is_private() || is_static() || is_strict() || is_synchronized()))
- {
- bool bout = false;
- REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
- _class->get_name()->bytes << ": invalid combination of access flags (ACC_ABSTRACT|"
- << ((bout = is_final())?"ACC_FINAL":"")
- << (bout?"|":"")
- << ((bout |= is_native())?"ACC_NATIVE":"")
- << (bout?"|":"")
- << ((bout |= is_private())?"ACC_PRIVATE":"")
- << (bout?"|":"")
- << ((bout |= is_static())?"ACC_STATIC":"")
- << (bout?"|":"")
- << ((bout |= is_strict())?"ACC_STRICT":"")
- << (bout?"|":"")
- << ((bout |= is_synchronized())?"ACC_SYNCHRONIZED":"")
- << ") for method "
- << _name->bytes << _descriptor->bytes);
- return false;
- }
if(_class->is_interface())
{
if(!(is_abstract() && is_public())){
REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
_class->get_name()->bytes << "." << _name->bytes << _descriptor->bytes
- << ": interface method must have access flags "
+ << ": interface method must have both access flags "
"ACC_ABSTRACT and ACC_PUBLIC set"
);
return false;
}
- if(_access_flags & ~(ACC_ABSTRACT | ACC_PUBLIC | ACC_VARARGS | ACC_BRIDGE | ACC_SYNTHETIC)){
+ if(_access_flags & ~(ACC_ABSTRACT | ACC_PUBLIC | ACC_VARARGS
+ | ACC_BRIDGE | ACC_SYNTHETIC)){
REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
- _class->get_name()->bytes << "." << _name->bytes << _descriptor->bytes
- << ": interface method cannot have access flags other then "
- "ACC_ABSTRACT, ACC_PUBLIC, ACC_VARARG, ACC_BRIDGES or ACC_SYNTHETIC set");
+ _class->get_name()->bytes << " 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_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
+ _class->get_name()->bytes << "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_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
+ _class->get_name()->bytes << " 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_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
+ _class->get_name()->bytes << " 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
@@ -1761,14 +1826,6 @@
_access_flags |= ACC_STATIC;
}
- if(is_init() && (is_static() || is_final() || is_synchronized() || is_native() || is_abstract() || is_bridge())) {
- REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
- _class->get_name()->bytes << "." << _name->bytes << _descriptor->bytes
- << ": constructor cannot have access flags other then "
- "ACC_STRICT, ACC_VARARGS, ACC_SYNTHETIC and one of ACC_PUBLIC, ACC_PRIVATE, or ACC_PROTECTED set");
- return false;
- }
-
//check method attributes
uint16 attr_count;
if(!cfs.parse_u2_be(&attr_count)) {
@@ -1823,16 +1880,43 @@
break;
case ATTR_RuntimeInvisibleParameterAnnotations:
- if(++numRuntimeInvisibleParameterAnnotations > 1) {
- REPORT_FAILED_CLASS_FORMAT(clss,
- "more than one RuntimeInvisibleParameterAnnotations attribute");
- return false;
- }
-
- if (!cfs.skip(attr_len))
{
- REPORT_FAILED_METHOD("error skipping RuntimeInvisibleParameterAnnotations");
- return false;
+ //RuntimeInvisibleParameterAnnotations attribute is parsed only if
+ //command line option -Xinvisible is set. See specification 4.8.17.
+ if(env.retain_invisible_annotations) {
+ 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,
+ "cannot parse number of InvisibleParameterAnnotations");
+ return false;
+ }
+ uint32 read_len = 1;
+ if (_num_invisible_param_annotations) {
+ uint32 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_METHOD("error skipping RuntimeInvisibleParameterAnnotations");
+ return false;
+ }
+ }
}
break;
@@ -1852,17 +1936,11 @@
}
uint32 read_len = 1;
if (_num_param_annotations) {
- _param_annotations = (AnnotationTable**)_class->get_class_loader()->Alloc(
- _num_param_annotations * sizeof (AnnotationTable*));
- //FIXME: verav should throw OOM
- for (unsigned i = 0; i < _num_param_annotations; i++)
- {
- uint32 next_len = parse_annotation_table(_param_annotations + i, cfs, _class);
- if (next_len == 0) {
- return false;
- }
- read_len += next_len;
- }
+ uint32 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(
@@ -1943,6 +2021,8 @@
}
uint32 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"
@@ -1961,11 +2041,26 @@
"more than one RuntimeInvisibleAnnotations attribute");
return false;
}
-
- if(!cfs.skip(attr_len)) {
- REPORT_FAILED_CLASS_FORMAT(clss,
- "failed to skip 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) {
+ uint32 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,
+ "failed to skip RuntimeInvisibleAnnotations attribute");
+ return false;
+ }
}
}
break;
@@ -2043,7 +2138,7 @@
unsigned short last_nonstatic_field = (unsigned short)num_fields_in_class_file;
for(i=0; i < num_fields_in_class_file; i++) {
Field fd;
- if(!fd.parse(this, cfs))
+ if(!fd.parse(*env, this, cfs))
return false;
if(fd.is_static()) {
m_fields[m_num_static_fields] = fd;
@@ -2170,14 +2265,14 @@
id_len++;
}else
{
- if(!check_field_name(name, id_len))
+ if(!check_field_name(name, id_len, false))
return false;
id_len = 0;
name = iterator;
name++;
}
}
- return check_field_name(name, id_len);
+ return check_field_name(name, id_len, false);
}
return false; //unreacheable code
}
@@ -2187,19 +2282,21 @@
{
// buffer ends before len
if(!cfs.have(len))
- return false;
+ return NULL;
// get utf8 bytes and move buffer pointer
- const char* utf8data = (const char*)cfs.get_and_skip(len);
+ uint8* utf8data = (uint8*)cfs.get_and_skip(len);
// FIXME: decode 6-byte Java 1.5 encoding
// check utf8 correctness
- if(memchr(utf8data, 0, len) != NULL)
- return false;
+ int i;
+ for(i = 0; i < len && utf8data[i] != 0x00 && utf8data[i] < 0xf0; i++);
+ if(i < len)
+ return NULL;
// then lookup on utf8 bytes and return string
- return string_pool.lookup(utf8data, len);
+ return string_pool.lookup((const char*)utf8data, len);
}
@@ -2208,7 +2305,7 @@
{
uint16 len;
if(!cfs.parse_u2_be(&len))
- return false;
+ return NULL;
return class_file_parse_utf8data(string_pool, cfs, len);
}
@@ -2304,7 +2401,11 @@
return false;
}
// skip next constant pool entry as it is used by next 4 bytes of Long/Double
- cp_tags[i+1] = cp_tags[i];
+ if(i + 1 < m_size) {
+ cp_tags[i+1] = CONSTANT_UnusedEntry;
+ m_entries[i+1].CONSTANT_8byte.high_bytes = m_entries[i].CONSTANT_8byte.high_bytes;
+ m_entries[i+1].CONSTANT_8byte.low_bytes = m_entries[i].CONSTANT_8byte.low_bytes;
+ }
i++;
break;
@@ -2337,7 +2438,7 @@
break;
default:
REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
- clss->get_name()->bytes << ": unknown constant pool tag " << cp_tags[i]);
+ clss->get_name()->bytes << ": unknown constant pool tag " << "0x" << std::hex << (int)cp_tags[i]);
return false;
}
}
@@ -2347,8 +2448,6 @@
bool ConstantPool::check(Global_Env* env, Class* clss)
{
-
-
for(unsigned i = 1; i < m_size; i++) {
switch(unsigned char tag = get_tag(i))
{
@@ -2409,7 +2508,8 @@
//check method name
if(name != env->Init_String)
{
- if(!check_method_name(name->bytes,name->len))
+ if(!check_method_name(name->bytes,name->len,
+ clss->get_version() < JAVA5_CLASS_FILE_VERSION))
{
REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
clss->get_name()->bytes << ": illegal method name for CONSTANT_Methodref entry: " << name->bytes);
@@ -2440,7 +2540,8 @@
if(tag == CONSTANT_Fieldref)
{
//check field name
- if(!check_field_name(name->bytes, name->len))
+ if(!check_field_name(name->bytes, name->len,
+ clss->get_version() < JAVA5_CLASS_FILE_VERSION))
{
REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
clss->get_name()->bytes << ": illegal filed name for CONSTANT_Filedref entry: " << name->bytes);
@@ -2458,7 +2559,8 @@
{
//check method name, name can't be or
//See specification 4.5.2 about name_and_type_index last sentence.
- if(!check_method_name(name->bytes, name->len))
+ if(!check_method_name(name->bytes, name->len,
+ clss->get_version() < JAVA5_CLASS_FILE_VERSION))
{
REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
clss->get_name()->bytes << ": illegal filed name for CONSTANT_InterfaceMethod entry: " << name->bytes);
@@ -2495,11 +2597,12 @@
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){
+ if(i + 1 == m_size){
REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
clss->get_name()->bytes << ": illegal indexes for Long or Double " << i << " and " << i + 1);
return false;
}
+ i++;
break;
case CONSTANT_NameAndType:
{
@@ -2647,7 +2750,7 @@
return false;
}
- if(m_version == 49 && minor_version > 0)
+ if(m_version == JAVA5_CLASS_FILE_VERSION && minor_version > 0)
{
REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/UnsupportedClassVersionError",
"unsupported class file version " << m_version << "." << minor_version);
@@ -2693,7 +2796,7 @@
REPORT_FAILED_CLASS_FORMAT(this, "interface cannot be final");
return false;
}
- //not only ACC_FINAL flag is prohibited if is_interface, also ACC_SUPER, ACC_SYNTHETIC, ACC_ENUM.
+ //not only ACC_FINAL flag is prohibited if is_interface, also ACC_SYNTHETIC and ACC_ENUM.
if(is_interface() && (is_synthetic() || is_enum()))
{
REPORT_FAILED_CLASS_FORMAT(this,
@@ -2716,7 +2819,12 @@
REPORT_FAILED_CLASS_FORMAT(this, "not interface can't be annotation");
return false;
}
-
+ //for class file version lower than 49 these three flags should be set to zero
+ //See specification 4.5 Fields, for 1.4 Java.
+ if(m_version < JAVA5_CLASS_FILE_VERSION) {
+ m_access_flags &= ~(ACC_SYNTHETIC | ACC_ENUM | ACC_ANNOTATION);
+ }
+
/*
* parse this_class & super_class & verify their constant pool entries
*/
@@ -3098,9 +3206,11 @@
return false;
}
uint32 read_len = parse_annotation_table(&m_annotations, cfs, this);
+ if(attr_len == 0)
+ return false;
if (attr_len != read_len) {
REPORT_FAILED_CLASS_FORMAT(this,
- "error parsing Annotations attribute"
+ "error parsing RuntimeVisibleAnnotations attribute"
<< "; declared length " << attr_len
<< " does not match actual " << read_len);
return false;
@@ -3110,17 +3220,30 @@
case ATTR_RuntimeInvisibleAnnotations:
{
- //ClassFile may contain at most one RuntimeInvisibleAnnotations attribute.
- if(++numRuntimeInvisibleAnnotations > 1) {
- REPORT_FAILED_CLASS_FORMAT(this,
- "more than one RuntimeInvisibleAnnotations attribute");
- return false;
+ if(env->retain_invisible_annotations) {
+ //ClassFile may contain at most one RuntimeInvisibleAnnotations attribute.
+ if(++numRuntimeInvisibleAnnotations > 1) {
+ REPORT_FAILED_CLASS_FORMAT(this,
+ "more than one RuntimeInvisibleAnnotations attribute");
+ return false;
+ }
+ uint32 read_len = parse_annotation_table(&m_invisible_annotations, cfs, this);
+ if(read_len == 0)
+ return false;
+ if (attr_len != read_len) {
+ REPORT_FAILED_CLASS_FORMAT(this,
+ "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(this,
+ "failed to skip RuntimeInvisibleAnnotations attribute");
+ return false;
+ }
}
- if(!cfs.skip(attr_len)) {
- REPORT_FAILED_CLASS_FORMAT(this,
- "failed to skip RuntimeInvisibleAnnotations attribute");
- return false;
- }
}
break;
Index: vm/vmcore/src/init/parse_arguments.cpp
===================================================================
--- vm/vmcore/src/init/parse_arguments.cpp (revision 490148)
+++ vm/vmcore/src/init/parse_arguments.cpp (working copy)
@@ -177,6 +177,8 @@
" Log verbose output to a file\n"
" -Xverify\n"
" Do full bytecode verification\n"
+ " -Xinvisible\n"
+ " Retain invisible annotations at runtime\n"
" -Xfileline\n"
" Add source information to logging messages\n"
" -Xthread\n"
@@ -435,6 +437,9 @@
else if (strcmp(option, "-Xdebug") == 0) {
// Do nothing, this option is only for compatibility with old JREs
}
+ else if (strcmp(option, "-Xinvisible") == 0) {
+ p_env->retain_invisible_annotations = true;
+ }
else if (strcmp(option, "-Xverify") == 0) {
p_env->verify_all = true;
}