From a21155c0c93135c6815dc814a7c5abd47eab7048 Mon Sep 17 00:00:00 2001 From: bothner Date: Sat, 26 Jan 2002 06:32:55 +0000 Subject: [PATCH] * verify.cc (verify_fail): Change from being a top-level function to e method of _Jv_BytecodeVerifier. Emit current method name. Pass the current verifier to type: and state: methods as needed, for better error messages, and for resolve. (resolve): Pass current class's loader for Class.forName and _Jv_FindClassFromSignature, rather than using the default loader. (various type: and state: methods): Take _Jv_BytecodeVerifier* arg. (get_type_val_for_signature): Make non-static. (various methods): Pass start_PC implicitly, not explicitly. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@49240 138bc75d-0d04-0410-961f-82ee72b054a4 --- libjava/verify.cc | 213 +++++++++++++++++++++++++++--------------------------- 1 file changed, 107 insertions(+), 106 deletions(-) diff --git a/libjava/verify.cc b/libjava/verify.cc index 24350ef..ac380cb 100644 --- a/libjava/verify.cc +++ b/libjava/verify.cc @@ -39,11 +39,6 @@ details. */ // * at least one GC problem :-( -// This is global because __attribute__ doesn't seem to work on static -// methods. -static void verify_fail (char *msg, jint pc = -1) - __attribute__ ((__noreturn__)); - static void debug_print (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); @@ -180,7 +175,7 @@ private: // Return the type_val corresponding to a primitive signature // character. For instance `I' returns `int.class'. - static type_val get_type_val_for_signature (jchar sig) + type_val get_type_val_for_signature (jchar sig) { type_val rt; switch (sig) @@ -219,7 +214,7 @@ private: } // Return the type_val corresponding to a primitive class. - static type_val get_type_val_for_signature (jclass k) + type_val get_type_val_for_signature (jclass k) { return get_type_val_for_signature ((jchar) k->method_count); } @@ -390,35 +385,36 @@ private: } // If *THIS is an unresolved reference type, resolve it. - void resolve () + void resolve (_Jv_BytecodeVerifier *verifier) { if (key != unresolved_reference_type && key != uninitialized_unresolved_reference_type) return; - // FIXME: class loader using namespace java::lang; + java::lang::ClassLoader *loader + = verifier->current_class->getClassLoader(); // We might see either kind of name. Sigh. if (data.name->data[0] == 'L' && data.name->data[data.name->length - 1] == ';') - data.klass = _Jv_FindClassFromSignature (data.name->data, NULL); + data.klass = _Jv_FindClassFromSignature (data.name->data, loader); else data.klass = Class::forName (_Jv_NewStringUtf8Const (data.name), - false, NULL); + false, loader); key = (key == unresolved_reference_type ? reference_type : uninitialized_reference_type); } // Mark this type as the uninitialized result of `new'. - void set_uninitialized (int npc) + void set_uninitialized (int npc, _Jv_BytecodeVerifier *verifier) { if (key == reference_type) key = uninitialized_reference_type; else if (key == unresolved_reference_type) key = uninitialized_unresolved_reference_type; else - verify_fail ("internal error in type::uninitialized"); + verifier->verify_fail ("internal error in type::uninitialized"); pc = npc; } @@ -441,7 +437,7 @@ private: // of type *THIS. Handle various special cases too. Might modify // *THIS or K. Note however that this does not perform numeric // promotion. - bool compatible (type &k) + bool compatible (type &k, _Jv_BytecodeVerifier *verifier) { // Any type is compatible with the unsuitable type. if (key == unsuitable_type) @@ -482,8 +478,8 @@ private: return true; // We must resolve both types and check assignability. - resolve (); - k.resolve (); + resolve (verifier); + k.resolve (verifier); return is_assignable_from_slow (data.klass, k.data.klass); } @@ -515,17 +511,17 @@ private: return false; } - bool isinterface () + bool isinterface (_Jv_BytecodeVerifier *verifier) { - resolve (); + resolve (verifier); if (key != reference_type) return false; return data.klass->isInterface (); } - bool isabstract () + bool isabstract (_Jv_BytecodeVerifier *verifier) { - resolve (); + resolve (verifier); if (key != reference_type) return false; using namespace java::lang::reflect; @@ -533,34 +529,34 @@ private: } // Return the element type of an array. - type element_type () + type element_type (_Jv_BytecodeVerifier *verifier) { // FIXME: maybe should do string manipulation here. - resolve (); + resolve (verifier); if (key != reference_type) - verify_fail ("programmer error in type::element_type()"); + verifier->verify_fail ("programmer error in type::element_type()", -1); jclass k = data.klass->getComponentType (); if (k->isPrimitive ()) - return type (get_type_val_for_signature (k)); + return type (verifier->get_type_val_for_signature (k)); return type (k); } // Return the array type corresponding to an initialized // reference. We could expand this to work for other kinds of // types, but currently we don't need to. - type to_array () + type to_array (_Jv_BytecodeVerifier *verifier) { // Resolving isn't ideal, because it might force us to load // another class, but it's easy. FIXME? if (key == unresolved_reference_type) - resolve (); + resolve (verifier); if (key == reference_type) return type (_Jv_GetArrayClass (data.klass, data.klass->getClassLoader ())); else - verify_fail ("internal error in type::to_array()"); + verifier->verify_fail ("internal error in type::to_array()"); } bool isreference () const @@ -587,7 +583,7 @@ private: || key == uninitialized_reference_type); } - void verify_dimensions (int ndims) + void verify_dimensions (int ndims, _Jv_BytecodeVerifier *verifier) { // The way this is written, we don't need to check isarray(). if (key == reference_type) @@ -608,11 +604,11 @@ private: } if (ndims > 0) - verify_fail ("array type has fewer dimensions than required"); + verifier->verify_fail ("array type has fewer dimensions than required"); } // Merge OLD_TYPE into this. On error throw exception. - bool merge (type& old_type, bool local_semantics = false) + bool merge (type& old_type, bool local_semantics, _Jv_BytecodeVerifier *verifier) { bool changed = false; bool refo = old_type.isreference (); @@ -627,7 +623,7 @@ private: changed = true; } else if (isinitialized () != old_type.isinitialized ()) - verify_fail ("merging initialized and uninitialized types"); + verifier->verify_fail ("merging initialized and uninitialized types"); else { if (! isinitialized ()) @@ -637,7 +633,7 @@ private: else if (old_type.pc == UNINIT) ; else if (pc != old_type.pc) - verify_fail ("merging different uninitialized types"); + verifier->verify_fail ("merging different uninitialized types"); } if (! isresolved () @@ -648,8 +644,8 @@ private: } else { - resolve (); - old_type.resolve (); + resolve (verifier); + old_type.resolve (verifier); jclass k = data.klass; jclass oldk = old_type.data.klass; @@ -708,7 +704,7 @@ private: } } else - verify_fail ("unmergeable type"); + verifier->verify_fail ("unmergeable type"); } return changed; } @@ -886,7 +882,7 @@ private: // state. Returns true if the new state was in fact changed. // Will throw an exception if the states are not mergeable. bool merge (state *state_old, bool ret_semantics, - int max_locals) + int max_locals, _Jv_BytecodeVerifier *verifier) { bool changed = false; @@ -908,14 +904,14 @@ private: changed = true; } else - verify_fail ("subroutines merged"); + verifier->verify_fail ("subroutines merged"); // Merge stacks. if (state_old->stacktop != stacktop) - verify_fail ("stack sizes differ"); + verifier->verify_fail ("stack sizes differ"); for (int i = 0; i < state_old->stacktop; ++i) { - if (stack[i].merge (state_old->stack[i])) + if (stack[i].merge (state_old->stack[i], false, verifier)) changed = true; } @@ -924,7 +920,7 @@ private: { if (! ret_semantics || local_changed[i]) { - if (locals[i].merge (state_old->locals[i], true)) + if (locals[i].merge (state_old->locals[i], true, verifier)) { changed = true; note_variable (i); @@ -945,27 +941,28 @@ private: // whether we're using backwards-branch or exception-handing // semantics. void check_no_uninitialized_objects (int max_locals, + _Jv_BytecodeVerifier *verifier, bool exception_semantics = false) { if (! exception_semantics) { for (int i = 0; i < stacktop; ++i) if (stack[i].isreference () && ! stack[i].isinitialized ()) - verify_fail ("uninitialized object on stack"); + verifier->verify_fail ("uninitialized object on stack"); } for (int i = 0; i < max_locals; ++i) if (locals[i].isreference () && ! locals[i].isinitialized ()) - verify_fail ("uninitialized object in local variable"); + verifier->verify_fail ("uninitialized object in local variable"); - check_this_initialized (); + check_this_initialized (verifier); } // Ensure that `this' has been initialized. - void check_this_initialized () + void check_this_initialized (_Jv_BytecodeVerifier *verifier) { if (this_type.isreference () && ! this_type.isinitialized ()) - verify_fail ("`this' is uninitialized"); + verifier->verify_fail ("`this' is uninitialized"); } // Set type of `this'. @@ -1028,7 +1025,7 @@ private: type pop_raw () { if (current_state->stacktop <= 0) - verify_fail ("stack empty", start_PC); + verify_fail ("stack empty"); type r = current_state->stack[--current_state->stacktop]; current_state->stackdepth -= r.depth (); if (current_state->stackdepth < 0) @@ -1040,7 +1037,7 @@ private: { type r = pop_raw (); if (r.iswide ()) - verify_fail ("narrow pop of wide type", start_PC); + verify_fail ("narrow pop of wide type"); return r; } @@ -1048,7 +1045,7 @@ private: { type r = pop_raw (); if (! r.iswide ()) - verify_fail ("wide pop of narrow type", start_PC); + verify_fail ("wide pop of narrow type"); return r; } @@ -1056,8 +1053,8 @@ private: { match.promote (); type t = pop_raw (); - if (! match.compatible (t)) - verify_fail ("incompatible type on stack", start_PC); + if (! match.compatible (t, this)) + verify_fail ("incompatible type on stack"); return t; } @@ -1066,7 +1063,7 @@ private: { type t = pop_raw (); if (! t.isreference () && t.key != return_address_type) - verify_fail ("expected reference or return address on stack", start_PC); + verify_fail ("expected reference or return address on stack"); return t; } @@ -1109,14 +1106,14 @@ private: { int depth = t.depth (); if (index > current_method->max_locals - depth) - verify_fail ("invalid local variable", start_PC); - if (! t.compatible (current_state->locals[index])) - verify_fail ("incompatible type in local variable", start_PC); + verify_fail ("invalid local variable"); + if (! t.compatible (current_state->locals[index], this)) + verify_fail ("incompatible type in local variable"); if (depth == 2) { type t (continuation_type); - if (! current_state->locals[index + 1].compatible (t)) - verify_fail ("invalid local variable", start_PC); + if (! current_state->locals[index + 1].compatible (t, this)) + verify_fail ("invalid local variable"); } return current_state->locals[index]; } @@ -1128,8 +1125,8 @@ private: if (! array.isarray ()) verify_fail ("array required"); - type t = array.element_type (); - if (! element.compatible (t)) + type t = array.element_type (this); + if (! element.compatible (t, this)) { // Special case for byte arrays, which must also be boolean // arrays. @@ -1137,7 +1134,7 @@ private: if (element.key == byte_type) { type e2 (boolean_type); - ok = e2.compatible (t); + ok = e2.compatible (t, this); } if (! ok) verify_fail ("incompatible array element type"); @@ -1217,7 +1214,7 @@ private: states[npc]->print (" To", npc, current_method->max_stack, current_method->max_locals); changed = states[npc]->merge (nstate, ret_semantics, - current_method->max_locals); + current_method->max_locals, this); states[npc]->print ("New", npc, current_method->max_stack, current_method->max_locals); } @@ -1235,14 +1232,14 @@ private: { int npc = compute_jump (offset); if (npc < PC) - current_state->check_no_uninitialized_objects (current_method->max_locals); + current_state->check_no_uninitialized_objects (current_method->max_locals, this); push_jump_merge (npc, current_state); } void push_exception_jump (type t, int pc) { current_state->check_no_uninitialized_objects (current_method->max_locals, - true); + this, true); state s (current_state, current_method->max_stack, current_method->max_locals); s.set_exception (t, current_method->max_stack); @@ -1336,7 +1333,7 @@ private: // in the enclosing context. current_state->subroutine = get_subroutine (subr->pc); if (subr->pc < PC) - current_state->check_no_uninitialized_objects (current_method->max_locals); + current_state->check_no_uninitialized_objects (current_method->max_locals, this); push_jump_merge (subr->pc, current_state, true); } @@ -1361,7 +1358,7 @@ private: int npc = compute_jump (offset); if (npc < PC) - current_state->check_no_uninitialized_objects (current_method->max_locals); + current_state->check_no_uninitialized_objects (current_method->max_locals, this); check_nonrecursive_call (current_state->subroutine, npc); // Temporarily modify the current state so that it looks like we are @@ -1899,8 +1896,8 @@ private: void check_return_type (type onstack) { type rt = compute_return_type (current_method->self->signature); - if (! rt.compatible (onstack)) - verify_fail ("incompatible return type", start_PC); + if (! rt.compatible (onstack, this)) + verify_fail ("incompatible return type"); } // Initialize the stack for the new method. Returns true if this @@ -1916,7 +1913,7 @@ private: type kurr (current_class); if (_Jv_equalUtf8Consts (current_method->self->name, gcj::init_name)) { - kurr.set_uninitialized (type::SELF); + kurr.set_uninitialized (type::SELF, this); is_init = true; } set_variable (0, kurr); @@ -1997,7 +1994,7 @@ private: current_state->print ("Cur", PC, current_method->max_stack, current_method->max_locals); if (! current_state->merge (states[PC], false, - current_method->max_locals) + current_method->max_locals, this) && ! states[PC]->is_unmerged_ret_state (current_method->max_locals)) { debug_print ("== Fall through optimization\n"); @@ -2610,7 +2607,7 @@ private: // We only need to check this when the return type is // void, because all instance initializers return void. if (this_is_init) - current_state->check_this_initialized (); + current_state->check_this_initialized (this); check_return_type (void_type); invalidate_pc (); break; @@ -2639,7 +2636,7 @@ private: // `this' has not yet been initialized. if (! current_state->this_type.isinitialized () && current_state->this_type.pc == type::SELF) - klass.set_uninitialized (type::SELF); + klass.set_uninitialized (type::SELF, this); pop_type (klass); } break; @@ -2660,14 +2657,11 @@ private: { int nargs = get_byte (); if (nargs == 0) - verify_fail ("too few arguments to invokeinterface", - start_PC); + verify_fail ("too few arguments to invokeinterface"); if (get_byte () != 0) - verify_fail ("invokeinterface dummy byte is wrong", - start_PC); + verify_fail ("invokeinterface dummy byte is wrong"); if (nargs - 1 != arg_count) - verify_fail ("wrong argument count for invokeinterface", - start_PC); + verify_fail ("wrong argument count for invokeinterface"); } bool is_init = false; @@ -2675,11 +2669,10 @@ private: { is_init = true; if (opcode != op_invokespecial) - verify_fail ("can't invoke ", start_PC); + verify_fail ("can't invoke "); } else if (method_name->data[0] == '<') - verify_fail ("can't invoke method starting with `<'", - start_PC); + verify_fail ("can't invoke method starting with `<'"); // Pop arguments and check types. type arg_types[arg_count]; @@ -2693,7 +2686,7 @@ private: if (is_init) { // In this case the PC doesn't matter. - t.set_uninitialized (type::UNINIT); + t.set_uninitialized (type::UNINIT, this); } t = pop_type (t); if (is_init) @@ -2710,10 +2703,9 @@ private: case op_new: { type t = check_class_constant (get_ushort ()); - if (t.isarray () || t.isinterface () || t.isabstract ()) - verify_fail ("type is array, interface, or abstract", - start_PC); - t.set_uninitialized (start_PC); + if (t.isarray () || t.isinterface (this) || t.isabstract (this)) + verify_fail ("type is array, interface, or abstract"); + t.set_uninitialized (start_PC, this); push_type (t); } break; @@ -2731,13 +2723,13 @@ private: break; case op_anewarray: pop_type (int_type); - push_type (check_class_constant (get_ushort ()).to_array ()); + push_type (check_class_constant (get_ushort ()).to_array (this)); break; case op_arraylength: { type t = pop_type (reference_type); if (! t.isarray ()) - verify_fail ("array type expected", start_PC); + verify_fail ("array type expected"); push_type (int_type); } break; @@ -2812,7 +2804,7 @@ private: int dim = get_byte (); if (dim < 1) verify_fail ("too few dimensions to multianewarray", start_PC); - atype.verify_dimensions (dim); + atype.verify_dimensions (dim, this); for (int i = 0; i < dim; ++i) pop_type (int_type); push_type (atype); @@ -2839,6 +2831,34 @@ private: } } + __attribute__ ((__noreturn__)) void verify_fail (char *s, jint pc = -1) + { + using namespace java::lang; + StringBuffer *buf = new StringBuffer (); + + buf->append (JvNewStringLatin1 ("verification failed")); + if (pc == -1) + pc = start_PC; + if (pc != -1) + { + buf->append (JvNewStringLatin1 (" at PC ")); + buf->append (pc); + } + + _Jv_InterpMethod *method = current_method; + buf->append (JvNewStringLatin1 (" in ")); + buf->append (current_class->getName()); + buf->append ((jchar) ':'); + buf->append (JvNewStringUTF (method->get_method()->name->data)); + buf->append ((jchar) '('); + buf->append (JvNewStringUTF (method->get_method()->signature->data)); + buf->append ((jchar) ')'); + + buf->append (JvNewStringLatin1 (": ")); + buf->append (JvNewStringLatin1 (s)); + throw new java::lang::VerifyError (buf->toString ()); + } + public: void verify_instructions () @@ -2889,23 +2909,4 @@ _Jv_VerifyMethod (_Jv_InterpMethod *meth) _Jv_BytecodeVerifier v (meth); v.verify_instructions (); } - -// FIXME: add more info, like PC, when required. -static void -verify_fail (char *s, jint pc) -{ - using namespace java::lang; - StringBuffer *buf = new StringBuffer (); - - buf->append (JvNewStringLatin1 ("verification failed")); - if (pc != -1) - { - buf->append (JvNewStringLatin1 (" at PC ")); - buf->append (pc); - } - buf->append (JvNewStringLatin1 (": ")); - buf->append (JvNewStringLatin1 (s)); - throw new java::lang::VerifyError (buf->toString ()); -} - #endif /* INTERPRETER */ -- 2.7.4