mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8051012: Regression in verifier for <init> method call from inside of a branch
Fix stackmap matching for branches. Reviewed-by: coleenp, lfoltan, acorn
This commit is contained in:
parent
7b1571089e
commit
f588cd1325
4 changed files with 15 additions and 41 deletions
|
@ -70,24 +70,26 @@ int StackMapTable::get_index_from_offset(int32_t offset) const {
|
||||||
|
|
||||||
bool StackMapTable::match_stackmap(
|
bool StackMapTable::match_stackmap(
|
||||||
StackMapFrame* frame, int32_t target,
|
StackMapFrame* frame, int32_t target,
|
||||||
bool match, bool update, ErrorContext* ctx, TRAPS) const {
|
bool match, bool update, bool handler, ErrorContext* ctx, TRAPS) const {
|
||||||
int index = get_index_from_offset(target);
|
int index = get_index_from_offset(target);
|
||||||
return match_stackmap(frame, target, index, match, update, ctx, THREAD);
|
return match_stackmap(frame, target, index, match, update, handler, ctx, THREAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match and/or update current_frame to the frame in stackmap table with
|
// Match and/or update current_frame to the frame in stackmap table with
|
||||||
// specified offset and frame index. Return true if the two frames match.
|
// specified offset and frame index. Return true if the two frames match.
|
||||||
|
// handler is true if the frame in stackmap_table is for an exception handler.
|
||||||
//
|
//
|
||||||
// The values of match and update are: _match__update_
|
// The values of match and update are: _match__update__handler
|
||||||
//
|
//
|
||||||
// checking a branch target/exception handler: true false
|
// checking a branch target: true false false
|
||||||
|
// checking an exception handler: true false true
|
||||||
// linear bytecode verification following an
|
// linear bytecode verification following an
|
||||||
// unconditional branch: false true
|
// unconditional branch: false true false
|
||||||
// linear bytecode verification not following an
|
// linear bytecode verification not following an
|
||||||
// unconditional branch: true true
|
// unconditional branch: true true false
|
||||||
bool StackMapTable::match_stackmap(
|
bool StackMapTable::match_stackmap(
|
||||||
StackMapFrame* frame, int32_t target, int32_t frame_index,
|
StackMapFrame* frame, int32_t target, int32_t frame_index,
|
||||||
bool match, bool update, ErrorContext* ctx, TRAPS) const {
|
bool match, bool update, bool handler, ErrorContext* ctx, TRAPS) const {
|
||||||
if (frame_index < 0 || frame_index >= _frame_count) {
|
if (frame_index < 0 || frame_index >= _frame_count) {
|
||||||
*ctx = ErrorContext::missing_stackmap(frame->offset());
|
*ctx = ErrorContext::missing_stackmap(frame->offset());
|
||||||
frame->verifier()->verify_error(
|
frame->verifier()->verify_error(
|
||||||
|
@ -98,11 +100,9 @@ bool StackMapTable::match_stackmap(
|
||||||
StackMapFrame *stackmap_frame = _frame_array[frame_index];
|
StackMapFrame *stackmap_frame = _frame_array[frame_index];
|
||||||
bool result = true;
|
bool result = true;
|
||||||
if (match) {
|
if (match) {
|
||||||
// when checking handler target, match == true && update == false
|
|
||||||
bool is_exception_handler = !update;
|
|
||||||
// Has direct control flow from last instruction, need to match the two
|
// Has direct control flow from last instruction, need to match the two
|
||||||
// frames.
|
// frames.
|
||||||
result = frame->is_assignable_to(stackmap_frame, is_exception_handler,
|
result = frame->is_assignable_to(stackmap_frame, handler,
|
||||||
ctx, CHECK_VERIFY_(frame->verifier(), result));
|
ctx, CHECK_VERIFY_(frame->verifier(), result));
|
||||||
}
|
}
|
||||||
if (update) {
|
if (update) {
|
||||||
|
@ -126,7 +126,7 @@ void StackMapTable::check_jump_target(
|
||||||
StackMapFrame* frame, int32_t target, TRAPS) const {
|
StackMapFrame* frame, int32_t target, TRAPS) const {
|
||||||
ErrorContext ctx;
|
ErrorContext ctx;
|
||||||
bool match = match_stackmap(
|
bool match = match_stackmap(
|
||||||
frame, target, true, false, &ctx, CHECK_VERIFY(frame->verifier()));
|
frame, target, true, false, false, &ctx, CHECK_VERIFY(frame->verifier()));
|
||||||
if (!match || (target < 0 || target >= _code_length)) {
|
if (!match || (target < 0 || target >= _code_length)) {
|
||||||
frame->verifier()->verify_error(ctx,
|
frame->verifier()->verify_error(ctx,
|
||||||
"Inconsistent stackmap frames at branch target %d", target);
|
"Inconsistent stackmap frames at branch target %d", target);
|
||||||
|
@ -134,7 +134,6 @@ void StackMapTable::check_jump_target(
|
||||||
}
|
}
|
||||||
// check if uninitialized objects exist on backward branches
|
// check if uninitialized objects exist on backward branches
|
||||||
check_new_object(frame, target, CHECK_VERIFY(frame->verifier()));
|
check_new_object(frame, target, CHECK_VERIFY(frame->verifier()));
|
||||||
frame->verifier()->update_furthest_jump(target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StackMapTable::check_new_object(
|
void StackMapTable::check_new_object(
|
||||||
|
|
|
@ -60,12 +60,12 @@ class StackMapTable : public StackObj {
|
||||||
// specified offset. Return true if the two frames match.
|
// specified offset. Return true if the two frames match.
|
||||||
bool match_stackmap(
|
bool match_stackmap(
|
||||||
StackMapFrame* current_frame, int32_t offset,
|
StackMapFrame* current_frame, int32_t offset,
|
||||||
bool match, bool update, ErrorContext* ctx, TRAPS) const;
|
bool match, bool update, bool handler, ErrorContext* ctx, TRAPS) const;
|
||||||
// Match and/or update current_frame to the frame in stackmap table with
|
// Match and/or update current_frame to the frame in stackmap table with
|
||||||
// specified offset and frame index. Return true if the two frames match.
|
// specified offset and frame index. Return true if the two frames match.
|
||||||
bool match_stackmap(
|
bool match_stackmap(
|
||||||
StackMapFrame* current_frame, int32_t offset, int32_t frame_index,
|
StackMapFrame* current_frame, int32_t offset, int32_t frame_index,
|
||||||
bool match, bool update, ErrorContext* ctx, TRAPS) const;
|
bool match, bool update, bool handler, ErrorContext* ctx, TRAPS) const;
|
||||||
|
|
||||||
// Check jump instructions. Make sure there are no uninitialized
|
// Check jump instructions. Make sure there are no uninitialized
|
||||||
// instances on backward branch.
|
// instances on backward branch.
|
||||||
|
|
|
@ -620,8 +620,6 @@ void ClassVerifier::verify_method(methodHandle m, TRAPS) {
|
||||||
// flow from current instruction to the next
|
// flow from current instruction to the next
|
||||||
// instruction in sequence
|
// instruction in sequence
|
||||||
|
|
||||||
set_furthest_jump(0);
|
|
||||||
|
|
||||||
Bytecodes::Code opcode;
|
Bytecodes::Code opcode;
|
||||||
while (!bcs.is_last_bytecode()) {
|
while (!bcs.is_last_bytecode()) {
|
||||||
// Check for recursive re-verification before each bytecode.
|
// Check for recursive re-verification before each bytecode.
|
||||||
|
@ -1780,7 +1778,7 @@ u2 ClassVerifier::verify_stackmap_table(u2 stackmap_index, u2 bci,
|
||||||
// If matched, current_frame will be updated by this method.
|
// If matched, current_frame will be updated by this method.
|
||||||
bool matches = stackmap_table->match_stackmap(
|
bool matches = stackmap_table->match_stackmap(
|
||||||
current_frame, this_offset, stackmap_index,
|
current_frame, this_offset, stackmap_index,
|
||||||
!no_control_flow, true, &ctx, CHECK_VERIFY_(this, 0));
|
!no_control_flow, true, false, &ctx, CHECK_VERIFY_(this, 0));
|
||||||
if (!matches) {
|
if (!matches) {
|
||||||
// report type error
|
// report type error
|
||||||
verify_error(ctx, "Instruction type does not match stack map");
|
verify_error(ctx, "Instruction type does not match stack map");
|
||||||
|
@ -1827,7 +1825,7 @@ void ClassVerifier::verify_exception_handler_targets(u2 bci, bool this_uninit, S
|
||||||
}
|
}
|
||||||
ErrorContext ctx;
|
ErrorContext ctx;
|
||||||
bool matches = stackmap_table->match_stackmap(
|
bool matches = stackmap_table->match_stackmap(
|
||||||
new_frame, handler_pc, true, false, &ctx, CHECK_VERIFY(this));
|
new_frame, handler_pc, true, false, true, &ctx, CHECK_VERIFY(this));
|
||||||
if (!matches) {
|
if (!matches) {
|
||||||
verify_error(ctx, "Stack map does not match the one at "
|
verify_error(ctx, "Stack map does not match the one at "
|
||||||
"exception handler %d", handler_pc);
|
"exception handler %d", handler_pc);
|
||||||
|
@ -2238,13 +2236,6 @@ void ClassVerifier::verify_invoke_init(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that this call is not jumped over.
|
|
||||||
if (bci < furthest_jump()) {
|
|
||||||
verify_error(ErrorContext::bad_code(bci),
|
|
||||||
"Bad <init> method call from inside of a branch");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure that this call is not done from within a TRY block because
|
// Make sure that this call is not done from within a TRY block because
|
||||||
// that can result in returning an incomplete object. Simply checking
|
// that can result in returning an incomplete object. Simply checking
|
||||||
// (bci >= start_pc) also ensures that this call is not done after a TRY
|
// (bci >= start_pc) also ensures that this call is not done after a TRY
|
||||||
|
|
|
@ -258,9 +258,6 @@ class ClassVerifier : public StackObj {
|
||||||
|
|
||||||
ErrorContext _error_context; // contains information about an error
|
ErrorContext _error_context; // contains information about an error
|
||||||
|
|
||||||
// Used to detect illegal jumps over calls to super() nd this() in ctors.
|
|
||||||
int32_t _furthest_jump;
|
|
||||||
|
|
||||||
void verify_method(methodHandle method, TRAPS);
|
void verify_method(methodHandle method, TRAPS);
|
||||||
char* generate_code_data(methodHandle m, u4 code_length, TRAPS);
|
char* generate_code_data(methodHandle m, u4 code_length, TRAPS);
|
||||||
void verify_exception_handler_table(u4 code_length, char* code_data,
|
void verify_exception_handler_table(u4 code_length, char* code_data,
|
||||||
|
@ -407,19 +404,6 @@ class ClassVerifier : public StackObj {
|
||||||
|
|
||||||
TypeOrigin ref_ctx(const char* str, TRAPS);
|
TypeOrigin ref_ctx(const char* str, TRAPS);
|
||||||
|
|
||||||
// Keep track of the furthest branch done in a method to make sure that
|
|
||||||
// there are no branches over calls to super() or this() from inside of
|
|
||||||
// a constructor.
|
|
||||||
int32_t furthest_jump() { return _furthest_jump; }
|
|
||||||
|
|
||||||
void set_furthest_jump(int32_t target) {
|
|
||||||
_furthest_jump = target;
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_furthest_jump(int32_t target) {
|
|
||||||
if (target > _furthest_jump) _furthest_jump = target;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline int ClassVerifier::change_sig_to_verificationType(
|
inline int ClassVerifier::change_sig_to_verificationType(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue