8058982: Better verification of an exceptional invokespecial

Throw VerifyError for illegal accesses

Reviewed-by: acorn, ahgross, coleenp
This commit is contained in:
Harold Seigel 2014-10-20 14:43:11 -04:00
parent 8daca859f8
commit 616b927160
2 changed files with 50 additions and 32 deletions

View file

@ -1555,14 +1555,14 @@ void ClassVerifier::verify_method(methodHandle m, TRAPS) {
case Bytecodes::_invokespecial :
case Bytecodes::_invokestatic :
verify_invoke_instructions(
&bcs, code_length, &current_frame,
&this_uninit, return_type, cp, CHECK_VERIFY(this));
&bcs, code_length, &current_frame, (bci >= ex_min && bci < ex_max),
&this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this));
no_control_flow = false; break;
case Bytecodes::_invokeinterface :
case Bytecodes::_invokedynamic :
verify_invoke_instructions(
&bcs, code_length, &current_frame,
&this_uninit, return_type, cp, CHECK_VERIFY(this));
&bcs, code_length, &current_frame, (bci >= ex_min && bci < ex_max),
&this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this));
no_control_flow = false; break;
case Bytecodes::_new :
{
@ -2406,8 +2406,9 @@ bool ClassVerifier::ends_in_athrow(u4 start_bc_offset) {
void ClassVerifier::verify_invoke_init(
RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type,
StackMapFrame* current_frame, u4 code_length, bool *this_uninit,
constantPoolHandle cp, TRAPS) {
StackMapFrame* current_frame, u4 code_length, bool in_try_block,
bool *this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table,
TRAPS) {
u2 bci = bcs->bci();
VerificationType type = current_frame->pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
@ -2423,28 +2424,36 @@ void ClassVerifier::verify_invoke_init(
return;
}
// Check if this call is done from inside of a TRY block. If so, make
// sure that all catch clause paths end in a throw. Otherwise, this
// can result in returning an incomplete object.
ExceptionTable exhandlers(_method());
int exlength = exhandlers.length();
for(int i = 0; i < exlength; i++) {
u2 start_pc = exhandlers.start_pc(i);
u2 end_pc = exhandlers.end_pc(i);
// If this invokespecial call is done from inside of a TRY block then make
// sure that all catch clause paths end in a throw. Otherwise, this can
// result in returning an incomplete object.
if (in_try_block) {
ExceptionTable exhandlers(_method());
int exlength = exhandlers.length();
for(int i = 0; i < exlength; i++) {
u2 start_pc = exhandlers.start_pc(i);
u2 end_pc = exhandlers.end_pc(i);
if (bci >= start_pc && bci < end_pc) {
if (!ends_in_athrow(exhandlers.handler_pc(i))) {
verify_error(ErrorContext::bad_code(bci),
"Bad <init> method call from after the start of a try block");
return;
} else if (VerboseVerification) {
ResourceMark rm;
tty->print_cr(
"Survived call to ends_in_athrow(): %s",
current_class()->name()->as_C_string());
if (bci >= start_pc && bci < end_pc) {
if (!ends_in_athrow(exhandlers.handler_pc(i))) {
verify_error(ErrorContext::bad_code(bci),
"Bad <init> method call from after the start of a try block");
return;
} else if (VerboseVerification) {
ResourceMark rm;
tty->print_cr(
"Survived call to ends_in_athrow(): %s",
current_class()->name()->as_C_string());
}
}
}
}
// Check the exception handler target stackmaps with the locals from the
// incoming stackmap (before initialize_object() changes them to outgoing
// state).
verify_exception_handler_targets(bci, true, current_frame,
stackmap_table, CHECK_VERIFY(this));
} // in_try_block
current_frame->initialize_object(type, current_type());
*this_uninit = true;
@ -2498,6 +2507,13 @@ void ClassVerifier::verify_invoke_init(
}
}
}
// Check the exception handler target stackmaps with the locals from the
// incoming stackmap (before initialize_object() changes them to outgoing
// state).
if (in_try_block) {
verify_exception_handler_targets(bci, *this_uninit, current_frame,
stackmap_table, CHECK_VERIFY(this));
}
current_frame->initialize_object(type, new_class_type);
} else {
verify_error(ErrorContext::bad_type(bci, current_frame->stack_top_ctx()),
@ -2526,8 +2542,8 @@ bool ClassVerifier::is_same_or_direct_interface(
void ClassVerifier::verify_invoke_instructions(
RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
bool *this_uninit, VerificationType return_type,
constantPoolHandle cp, TRAPS) {
bool in_try_block, bool *this_uninit, VerificationType return_type,
constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS) {
// Make sure the constant pool item is the right type
u2 index = bcs->get_index_u2();
Bytecodes::Code opcode = bcs->raw_code();
@ -2693,7 +2709,8 @@ void ClassVerifier::verify_invoke_instructions(
opcode != Bytecodes::_invokedynamic) {
if (method_name == vmSymbols::object_initializer_name()) { // <init> method
verify_invoke_init(bcs, index, ref_class_type, current_frame,
code_length, this_uninit, cp, CHECK_VERIFY(this));
code_length, in_try_block, this_uninit, cp, stackmap_table,
CHECK_VERIFY(this));
} else { // other methods
// Ensures that target class is assignable to method class.
if (opcode == Bytecodes::_invokespecial) {