mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8058982: Better verification of an exceptional invokespecial
Throw VerifyError for illegal accesses Reviewed-by: acorn, ahgross, coleenp
This commit is contained in:
parent
8daca859f8
commit
616b927160
2 changed files with 50 additions and 32 deletions
|
@ -1555,14 +1555,14 @@ void ClassVerifier::verify_method(methodHandle m, TRAPS) {
|
|||
case Bytecodes::_invokespecial :
|
||||
case Bytecodes::_invokestatic :
|
||||
verify_invoke_instructions(
|
||||
&bcs, code_length, ¤t_frame,
|
||||
&this_uninit, return_type, cp, CHECK_VERIFY(this));
|
||||
&bcs, code_length, ¤t_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, ¤t_frame,
|
||||
&this_uninit, return_type, cp, CHECK_VERIFY(this));
|
||||
&bcs, code_length, ¤t_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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue