X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=libjava%2Fverify.cc;h=b002c1c0aabfb99ec7aeec267aef64a7a59876cc;hb=9a1f41f03ac0f7c491aa48bde989a67a2af6359c;hp=988b5aab67ee6139a0d83a2ee383cb83e178cd33;hpb=a4ccc41f9a5f050d518b8c30739a647f67756f9e;p=pf3gnuchains%2Fgcc-fork.git diff --git a/libjava/verify.cc b/libjava/verify.cc index 988b5aab67e..b002c1c0aab 100644 --- a/libjava/verify.cc +++ b/libjava/verify.cc @@ -1,6 +1,6 @@ // verify.cc - verify bytecode -/* Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation +/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation This file is part of libgcj. @@ -14,6 +14,8 @@ details. */ #include +#include + #include #include #include @@ -31,6 +33,7 @@ details. */ #include #include #include +#include #ifdef VERIFY_DEBUG #include @@ -203,7 +206,7 @@ private: return r; } - __attribute__ ((__noreturn__)) void verify_fail (char *s, jint pc = -1) + __attribute__ ((__noreturn__)) void verify_fail (const char *s, jint pc = -1) { using namespace java::lang; StringBuffer *buf = new StringBuffer (); @@ -323,7 +326,7 @@ private: bool equals (ref_intersection *other, _Jv_BytecodeVerifier *verifier) { if (! is_resolved && ! other->is_resolved - && _Jv_equalUtf8Consts (data.name, other->data.name)) + && _Jv_equalUtf8Classnames (data.name, other->data.name)) return true; if (! is_resolved) resolve (verifier); @@ -363,12 +366,23 @@ private: if (is_resolved) return; + // This is useful if you want to see which classes have to be resolved + // while doing the class verification. + debug_print("resolving class: %s\n", data.name->chars()); + using namespace java::lang; java::lang::ClassLoader *loader = verifier->current_class->getClassLoaderInternal(); - // We might see either kind of name. Sigh. - if (data.name->first() == 'L' && data.name->limit()[-1] == ';') - data.klass = _Jv_FindClassFromSignature (data.name->chars(), loader); + + // Due to special handling in to_array() array classes will always + // be of the "L ... ;" kind. The separator char ('.' or '/' may vary + // however. + if (data.name->limit()[-1] == ';') + { + data.klass = _Jv_FindClassFromSignature (data.name->chars(), loader); + if (data.klass == NULL) + throw new java::lang::NoClassDefFoundError(data.name->toString()); + } else data.klass = Class::forName (_Jv_NewStringUtf8Const (data.name), false, loader); @@ -392,12 +406,21 @@ private: // Avoid resolving if possible. if (! self->is_resolved && ! other_iter->is_resolved - && _Jv_equalUtf8Consts (self->data.name, - other_iter->data.name)) + && _Jv_equalUtf8Classnames (self->data.name, + other_iter->data.name)) continue; if (! self->is_resolved) self->resolve(verifier); + + // If the LHS of the expression is of type + // java.lang.Object, assignment will succeed, no matter + // what the type of the RHS is. Using this short-cut we + // don't need to resolve the class of the RHS at + // verification time. + if (self->data.klass == &java::lang::Object::class$) + continue; + if (! other_iter->is_resolved) other_iter->resolve(verifier); @@ -578,9 +601,11 @@ private: // // First, when constructing a new object, it is the PC of the // `new' instruction which created the object. We use the special - // value UNINIT to mean that this is uninitialized, and the - // special value SELF for the case where the current method is - // itself the method. + // value UNINIT to mean that this is uninitialized. The special + // value SELF is used for the case where the current method is + // itself the method. the special value EITHER is used + // when we may optionally allow either an uninitialized or + // initialized reference to match. // // Second, when the key is return_address_type, this holds the PC // of the instruction following the `jsr'. @@ -588,6 +613,7 @@ private: static const int UNINIT = -2; static const int SELF = -1; + static const int EITHER = -3; // Basic constructor. type () @@ -734,23 +760,51 @@ private: if (k.klass == NULL) verifier->verify_fail ("programmer error in type::compatible"); - // An initialized type and an uninitialized type are not - // compatible. - if (isinitialized () != k.isinitialized ()) - return false; - - // Two uninitialized objects are compatible if either: - // * The PCs are identical, or - // * One PC is UNINIT. - if (! isinitialized ()) + // Handle the special 'EITHER' case, which is only used in a + // special case of 'putfield'. Note that we only need to handle + // this on the LHS of a check. + if (! isinitialized () && pc == EITHER) { - if (pc != k.pc && pc != UNINIT && k.pc != UNINIT) + // If the RHS is uninitialized, it must be an uninitialized + // 'this'. + if (! k.isinitialized () && k.pc != SELF) return false; } + else if (isinitialized () != k.isinitialized ()) + { + // An initialized type and an uninitialized type are not + // otherwise compatible. + return false; + } + else + { + // Two uninitialized objects are compatible if either: + // * The PCs are identical, or + // * One PC is UNINIT. + if (! isinitialized ()) + { + if (pc != k.pc && pc != UNINIT && k.pc != UNINIT) + return false; + } + } return klass->compatible(k.klass, verifier); } + bool equals (const type &other, _Jv_BytecodeVerifier *vfy) + { + // Only works for reference types. + if ((key != reference_type + && key != uninitialized_reference_type) + || (other.key != reference_type + && other.key != uninitialized_reference_type)) + return false; + // Only for single-valued types. + if (klass->ref_next || other.klass->ref_next) + return false; + return klass->equals (other.klass, vfy); + } + bool isvoid () const { return key == void_type; @@ -816,9 +870,70 @@ private: if (key != reference_type) verifier->verify_fail ("internal error in type::to_array()"); - jclass k = klass->getclass (verifier); - return type (_Jv_GetArrayClass (k, k->getClassLoaderInternal()), - verifier); + // In case the class is already resolved we can simply ask the runtime + // to give us the array version. + // If it is not resolved we prepend "[" to the classname to make the + // array usage verification more lazy. In other words: makes new Foo[300] + // pass the verifier if Foo.class is missing. + if (klass->is_resolved) + { + jclass k = klass->getclass (verifier); + + return type (_Jv_GetArrayClass (k, k->getClassLoaderInternal()), + verifier); + } + else + { + int len = klass->data.name->len(); + + // If the classname is given in the Lp1/p2/cn; format we only need + // to add a leading '['. The same procedure has to be done for + // primitive arrays (ie. provided "[I", the result should be "[[I". + // If the classname is given as p1.p2.cn we have to embed it into + // "[L" and ';'. + if (klass->data.name->limit()[-1] == ';' || + _Jv_isPrimitiveOrDerived(klass->data.name)) + { + // Reserves space for leading '[' and trailing '\0' . + char arrayName[len + 2]; + + arrayName[0] = '['; + strcpy(&arrayName[1], klass->data.name->chars()); + +#ifdef VERIFY_DEBUG + // This is only needed when we want to print the string to the + // screen while debugging. + arrayName[len + 1] = '\0'; + + debug_print("len: %d - old: '%s' - new: '%s'\n", len, klass->data.name->chars(), arrayName); +#endif + + return type (verifier->make_utf8_const( arrayName, len + 1 ), + verifier); + } + else + { + // Reserves space for leading "[L" and trailing ';' and '\0' . + char arrayName[len + 4]; + + arrayName[0] = '['; + arrayName[1] = 'L'; + strcpy(&arrayName[2], klass->data.name->chars()); + arrayName[len + 2] = ';'; + +#ifdef VERIFY_DEBUG + // This is only needed when we want to print the string to the + // screen while debugging. + arrayName[len + 3] = '\0'; + + debug_print("len: %d - old: '%s' - new: '%s'\n", len, klass->data.name->chars(), arrayName); +#endif + + return type (verifier->make_utf8_const( arrayName, len + 3 ), + verifier); + } + } + } bool isreference () const @@ -1861,6 +1976,7 @@ private: case op_getstatic_4: case op_getstatic_8: case op_getstatic_a: + case op_breakpoint: default: verify_fail ("unrecognized instruction in branch_prepass", start_PC); @@ -1914,13 +2030,16 @@ private: { check_pool_index (index); _Jv_Constants *pool = ¤t_class->constants; - if (pool->tags[index] == JV_CONSTANT_ResolvedString - || pool->tags[index] == JV_CONSTANT_String) + int tag = pool->tags[index]; + if (tag == JV_CONSTANT_ResolvedString || tag == JV_CONSTANT_String) return type (&java::lang::String::class$, this); - else if (pool->tags[index] == JV_CONSTANT_Integer) + else if (tag == JV_CONSTANT_Integer) return type (int_type); - else if (pool->tags[index] == JV_CONSTANT_Float) + else if (tag == JV_CONSTANT_Float) return type (float_type); + else if (current_method->is_15 + && (tag == JV_CONSTANT_ResolvedClass || tag == JV_CONSTANT_Class)) + return type (&java::lang::Class::class$, this); verify_fail ("String, int, or float constant expected", start_PC); } @@ -1963,7 +2082,9 @@ private: } // Return field's type, compute class' type if requested. - type check_field_constant (int index, type *class_type = NULL) + // If PUTFIELD is true, use the special 'putfield' semantics. + type check_field_constant (int index, type *class_type = NULL, + bool putfield = false) { _Jv_Utf8Const *name, *field_type; type ct = handle_field_or_method (index, @@ -1971,9 +2092,29 @@ private: &name, &field_type); if (class_type) *class_type = ct; + type result; if (field_type->first() == '[' || field_type->first() == 'L') - return type (field_type, this); - return get_type_val_for_signature (field_type->first()); + result = type (field_type, this); + else + result = get_type_val_for_signature (field_type->first()); + + // We have an obscure special case here: we can use `putfield' on + // a field declared in this class, even if `this' has not yet been + // initialized. + if (putfield + && ! current_state->this_type.isinitialized () + && current_state->this_type.pc == type::SELF + && current_state->this_type.equals (ct, this) + // We don't look at the signature, figuring that if it is + // wrong we will fail during linking. FIXME? + && _Jv_Linker::has_field_p (current_class, name)) + // Note that we don't actually know whether we're going to match + // against 'this' or some other object of the same type. So, + // here we set things up so that it doesn't matter. This relies + // on knowing what our caller is up to. + class_type->set_uninitialized (type::EITHER, this); + + return result; } type check_method_constant (int index, bool is_interface, @@ -2140,8 +2281,9 @@ private: // We only have to do this checking in the situation where // control flow falls through from the previous // instruction. Otherwise merging is done at the time we - // push the branch. - if (states[PC] != NULL) + // push the branch. Note that we'll catch the + // off-the-end problem just below. + if (PC < current_method->code_length && states[PC] != NULL) { // We've already visited this instruction. So merge // the states together. It is simplest, but not most @@ -2783,15 +2925,8 @@ private: case op_putfield: { type klass; - type field = check_field_constant (get_ushort (), &klass); + type field = check_field_constant (get_ushort (), &klass, true); pop_type (field); - - // We have an obscure special case here: we can use - // `putfield' on a field declared in this class, even if - // `this' has not yet been initialized. - if (! current_state->this_type.isinitialized () - && current_state->this_type.pc == type::SELF) - klass.set_uninitialized (type::SELF, this); pop_type (klass); } break; @@ -2874,8 +3009,8 @@ private: case op_new: { type t = check_class_constant (get_ushort ()); - if (t.isarray () || t.isinterface (this) || t.isabstract (this)) - verify_fail ("type is array, interface, or abstract"); + if (t.isarray ()) + verify_fail ("type is array"); t.set_uninitialized (start_PC, this); push_type (t); } @@ -3019,6 +3154,7 @@ private: case op_getstatic_4: case op_getstatic_8: case op_getstatic_a: + case op_breakpoint: default: // Unrecognized opcode. verify_fail ("unrecognized instruction in verify_instructions_0",