aboutsummaryrefslogtreecommitdiff
path: root/libjava/verify.cc
diff options
context:
space:
mode:
authortromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>2001-12-10 01:18:30 +0000
committertromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>2001-12-10 01:18:30 +0000
commit91b931f99911a9111788d681600e0b9efa7f9c9e (patch)
tree45cc1d1d0e9f8a64a919f48430d377afbd8b126c /libjava/verify.cc
parent460ee42fcdab0bf053c4365bb2258d119c7d9de5 (diff)
* resolve.cc (_Jv_PrepareClass): Verify method here...
* defineclass.cc (handleMethodsEnd): ... not here. * verify.cc (_Jv_BytecodeVerifier::initialize_stack): New method. (_Jv_BytecodeVerifier::verify_instructions_0) [op_return]: Ensure there are no uninitialized objects. (_Jv_BytecodeVerifier::state::this_type): New field. (_Jv_BytecodeVerifier::state::state): Initialize this_type. (_Jv_BytecodeVerifier::state::copy): Copy this_type. (_Jv_BytecodeVerifier::state::merge): Merge this_type. (_Jv_BytecodeVerifier::state::check_no_uninitialized_objects): Handle this_type. (_Jv_BytecodeVerifier::state::check_this_initialized): New method. (_Jv_BytecodeVerifier::state::set_initialized): Handle this_type. (_Jv_BytecodeVerifier::state::set_this_type): New method. (_Jv_BytecodeVerifier::verify_instructions_0) [op_putfield]: Allow assignment to fields of `this' before another initializer is run. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@47826 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/verify.cc')
-rw-r--r--libjava/verify.cc111
1 files changed, 83 insertions, 28 deletions
diff --git a/libjava/verify.cc b/libjava/verify.cc
index 74499ed4fa1..8627de571c3 100644
--- a/libjava/verify.cc
+++ b/libjava/verify.cc
@@ -764,6 +764,13 @@ private:
// This is used to keep a linked list of all the states which
// require re-verification. We use the PC to keep track.
int next;
+ // We keep track of the type of `this' specially. This is used to
+ // ensure that an instance initializer invokes another initializer
+ // on `this' before returning. We must keep track of this
+ // specially because otherwise we might be confused by code which
+ // assigns to locals[0] (overwriting `this') and then returns
+ // without really initializing.
+ type this_type;
// INVALID marks a state which is not on the linked list of states
// requiring reverification.
@@ -772,6 +779,7 @@ private:
static const int NO_NEXT = -2;
state ()
+ : this_type ()
{
stack = NULL;
locals = NULL;
@@ -779,6 +787,7 @@ private:
}
state (int max_stack, int max_locals)
+ : this_type ()
{
stacktop = 0;
stackdepth = 0;
@@ -855,6 +864,7 @@ private:
locals[i] = copy->locals[i];
local_changed[i] = copy->local_changed[i];
}
+ this_type = copy->this_type;
// Don't modify `next'.
}
@@ -870,14 +880,19 @@ private:
// FIXME: subroutine handling?
}
- // Merge STATE into this state. Destructively modifies this state.
- // Returns true if the new state was in fact changed. Will throw an
- // exception if the states are not mergeable.
+ // Merge STATE_OLD into this state. Destructively modifies this
+ // 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)
{
bool changed = false;
+ // Special handling for `this'. If one or the other is
+ // uninitialized, then the merge is uninitialized.
+ if (this_type.isinitialized ())
+ this_type = state_old->this_type;
+
// Merge subroutine states. *THIS and *STATE_OLD must be in the
// same subroutine. Also, recursive subroutine calls must be
// avoided.
@@ -940,6 +955,21 @@ private:
for (int i = 0; i < max_locals; ++i)
if (locals[i].isreference () && ! locals[i].isinitialized ())
verify_fail ("uninitialized object in local variable");
+
+ check_this_initialized ();
+ }
+
+ // Ensure that `this' has been initialized.
+ void check_this_initialized ()
+ {
+ if (this_type.isreference () && ! this_type.isinitialized ())
+ verify_fail ("`this' is uninitialized");
+ }
+
+ // Set type of `this'.
+ void set_this_type (const type &k)
+ {
+ this_type = k;
}
// Note that a local variable was modified.
@@ -957,6 +987,7 @@ private:
stack[i].set_initialized (pc);
for (int i = 0; i < max_locals; ++i)
locals[i].set_initialized (pc);
+ this_type.set_initialized (pc);
}
// Return true if this state is the unmerged result of a `ret'.
@@ -1870,6 +1901,42 @@ private:
verify_fail ("incompatible return type", start_PC);
}
+ // Initialize the stack for the new method. Returns true if this
+ // method is an instance initializer.
+ bool initialize_stack ()
+ {
+ int var = 0;
+ bool is_init = false;
+
+ using namespace java::lang::reflect;
+ if (! Modifier::isStatic (current_method->self->accflags))
+ {
+ type kurr (current_class);
+ if (_Jv_equalUtf8Consts (current_method->self->name, gcj::init_name))
+ {
+ kurr.set_uninitialized (type::SELF);
+ is_init = true;
+ }
+ set_variable (0, kurr);
+ current_state->set_this_type (kurr);
+ ++var;
+ }
+
+ // We have to handle wide arguments specially here.
+ int arg_count = _Jv_count_arguments (current_method->self->signature);
+ type arg_types[arg_count];
+ compute_argument_types (current_method->self->signature, arg_types);
+ for (int i = 0; i < arg_count; ++i)
+ {
+ set_variable (var, arg_types[i]);
+ ++var;
+ if (arg_types[i].iswide ())
+ ++var;
+ }
+
+ return is_init;
+ }
+
void verify_instructions_0 ()
{
current_state = new state (current_method->max_stack,
@@ -1878,31 +1945,8 @@ private:
PC = 0;
start_PC = 0;
- {
- int var = 0;
-
- using namespace java::lang::reflect;
- if (! Modifier::isStatic (current_method->self->accflags))
- {
- type kurr (current_class);
- if (_Jv_equalUtf8Consts (current_method->self->name, gcj::init_name))
- kurr.set_uninitialized (type::SELF);
- set_variable (0, kurr);
- ++var;
- }
-
- // We have to handle wide arguments specially here.
- int arg_count = _Jv_count_arguments (current_method->self->signature);
- type arg_types[arg_count];
- compute_argument_types (current_method->self->signature, arg_types);
- for (int i = 0; i < arg_count; ++i)
- {
- set_variable (var, arg_types[i]);
- ++var;
- if (arg_types[i].iswide ())
- ++var;
- }
- }
+ // True if we are verifying an instance initializer.
+ bool this_is_init = initialize_stack ();
states = (state **) _Jv_Malloc (sizeof (state *)
* current_method->code_length);
@@ -2561,6 +2605,10 @@ private:
invalidate_pc ();
break;
case op_return:
+ // 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 ();
check_return_type (void_type);
invalidate_pc ();
break;
@@ -2583,6 +2631,13 @@ private:
type klass;
type field = check_field_constant (get_ushort (), &klass);
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);
pop_type (klass);
}
break;