提交 0bea3bc6 编写于 作者: A asaha

Merge

...@@ -515,4 +515,5 @@ f3f50c4f9ea5d3af40cb794b6f3f2a337c8873db jdk8u25-b08 ...@@ -515,4 +515,5 @@ f3f50c4f9ea5d3af40cb794b6f3f2a337c8873db jdk8u25-b08
9e2bb00a81910776d5b16c49a3f4c5264ceab522 jdk8u25-b11 9e2bb00a81910776d5b16c49a3f4c5264ceab522 jdk8u25-b11
2993491d47df8c4b096ea7fa534162bde8b53dcf jdk8u25-b12 2993491d47df8c4b096ea7fa534162bde8b53dcf jdk8u25-b12
ca6d25be853b5c428c6228871316671843264666 jdk8u25-b13 ca6d25be853b5c428c6228871316671843264666 jdk8u25-b13
c77d5db189422e2eef0443ee212644e497113b18 jdk8u25-b14
5bb683bbe2c74876d585b5c3232fc3aab7b23e97 jdk8u31-b00 5bb683bbe2c74876d585b5c3232fc3aab7b23e97 jdk8u31-b00
...@@ -54,21 +54,6 @@ StackMapFrame* StackMapFrame::frame_in_exception_handler(u1 flags) { ...@@ -54,21 +54,6 @@ StackMapFrame* StackMapFrame::frame_in_exception_handler(u1 flags) {
return frame; return frame;
} }
bool StackMapFrame::has_new_object() const {
int32_t i;
for (i = 0; i < _max_locals; i++) {
if (_locals[i].is_uninitialized()) {
return true;
}
}
for (i = 0; i < _stack_size; i++) {
if (_stack[i].is_uninitialized()) {
return true;
}
}
return false;
}
void StackMapFrame::initialize_object( void StackMapFrame::initialize_object(
VerificationType old_object, VerificationType new_object) { VerificationType old_object, VerificationType new_object) {
int32_t i; int32_t i;
......
...@@ -154,10 +154,6 @@ class StackMapFrame : public ResourceObj { ...@@ -154,10 +154,6 @@ class StackMapFrame : public ResourceObj {
VerificationType set_locals_from_arg( VerificationType set_locals_from_arg(
const methodHandle m, VerificationType thisKlass, TRAPS); const methodHandle m, VerificationType thisKlass, TRAPS);
// Search local variable type array and stack type array.
// Return true if an uninitialized object is found.
bool has_new_object() const;
// Search local variable type array and stack type array. // Search local variable type array and stack type array.
// Set every element with type of old_object to new_object. // Set every element with type of old_object to new_object.
void initialize_object( void initialize_object(
......
...@@ -130,19 +130,6 @@ void StackMapTable::check_jump_target( ...@@ -130,19 +130,6 @@ void StackMapTable::check_jump_target(
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);
return;
}
// check if uninitialized objects exist on backward branches
check_new_object(frame, target, CHECK_VERIFY(frame->verifier()));
}
void StackMapTable::check_new_object(
const StackMapFrame* frame, int32_t target, TRAPS) const {
if (frame->offset() > target && frame->has_new_object()) {
frame->verifier()->verify_error(
ErrorContext::bad_code(frame->offset()),
"Uninitialized object exists on backward branch %d", target);
return;
} }
} }
......
...@@ -90,10 +90,6 @@ class StackMapTable : public StackObj { ...@@ -90,10 +90,6 @@ class StackMapTable : public StackObj {
// Returns the frame array index where the frame with offset is stored. // Returns the frame array index where the frame with offset is stored.
int get_index_from_offset(int32_t offset) const; int get_index_from_offset(int32_t offset) const;
// Make sure that there's no uninitialized object exist on backward branch.
void check_new_object(
const StackMapFrame* frame, int32_t target, TRAPS) const;
void print_on(outputStream* str) const; void print_on(outputStream* str) const;
}; };
......
...@@ -2231,6 +2231,181 @@ void ClassVerifier::verify_field_instructions(RawBytecodeStream* bcs, ...@@ -2231,6 +2231,181 @@ void ClassVerifier::verify_field_instructions(RawBytecodeStream* bcs,
} }
} }
// Look at the method's handlers. If the bci is in the handler's try block
// then check if the handler_pc is already on the stack. If not, push it.
void ClassVerifier::push_handlers(ExceptionTable* exhandlers,
GrowableArray<u4>* handler_stack,
u4 bci) {
int exlength = exhandlers->length();
for(int x = 0; x < exlength; x++) {
if (bci >= exhandlers->start_pc(x) && bci < exhandlers->end_pc(x)) {
handler_stack->append_if_missing(exhandlers->handler_pc(x));
}
}
}
// Return TRUE if all code paths starting with start_bc_offset end in
// bytecode athrow or loop.
bool ClassVerifier::ends_in_athrow(u4 start_bc_offset) {
ResourceMark rm;
// Create bytecode stream.
RawBytecodeStream bcs(method());
u4 code_length = method()->code_size();
bcs.set_start(start_bc_offset);
u4 target;
// Create stack for storing bytecode start offsets for if* and *switch.
GrowableArray<u4>* bci_stack = new GrowableArray<u4>(30);
// Create stack for handlers for try blocks containing this handler.
GrowableArray<u4>* handler_stack = new GrowableArray<u4>(30);
// Create list of visited branch opcodes (goto* and if*).
GrowableArray<u4>* visited_branches = new GrowableArray<u4>(30);
ExceptionTable exhandlers(_method());
while (true) {
if (bcs.is_last_bytecode()) {
// if no more starting offsets to parse or if at the end of the
// method then return false.
if ((bci_stack->is_empty()) || ((u4)bcs.end_bci() == code_length))
return false;
// Pop a bytecode starting offset and scan from there.
bcs.set_start(bci_stack->pop());
}
Bytecodes::Code opcode = bcs.raw_next();
u4 bci = bcs.bci();
// If the bytecode is in a TRY block, push its handlers so they
// will get parsed.
push_handlers(&exhandlers, handler_stack, bci);
switch (opcode) {
case Bytecodes::_if_icmpeq:
case Bytecodes::_if_icmpne:
case Bytecodes::_if_icmplt:
case Bytecodes::_if_icmpge:
case Bytecodes::_if_icmpgt:
case Bytecodes::_if_icmple:
case Bytecodes::_ifeq:
case Bytecodes::_ifne:
case Bytecodes::_iflt:
case Bytecodes::_ifge:
case Bytecodes::_ifgt:
case Bytecodes::_ifle:
case Bytecodes::_if_acmpeq:
case Bytecodes::_if_acmpne:
case Bytecodes::_ifnull:
case Bytecodes::_ifnonnull:
target = bcs.dest();
if (visited_branches->contains(bci)) {
if (bci_stack->is_empty()) return true;
// Pop a bytecode starting offset and scan from there.
bcs.set_start(bci_stack->pop());
} else {
if (target > bci) { // forward branch
if (target >= code_length) return false;
// Push the branch target onto the stack.
bci_stack->push(target);
// then, scan bytecodes starting with next.
bcs.set_start(bcs.next_bci());
} else { // backward branch
// Push bytecode offset following backward branch onto the stack.
bci_stack->push(bcs.next_bci());
// Check bytecodes starting with branch target.
bcs.set_start(target);
}
// Record target so we don't branch here again.
visited_branches->append(bci);
}
break;
case Bytecodes::_goto:
case Bytecodes::_goto_w:
target = (opcode == Bytecodes::_goto ? bcs.dest() : bcs.dest_w());
if (visited_branches->contains(bci)) {
if (bci_stack->is_empty()) return true;
// Been here before, pop new starting offset from stack.
bcs.set_start(bci_stack->pop());
} else {
if (target >= code_length) return false;
// Continue scanning from the target onward.
bcs.set_start(target);
// Record target so we don't branch here again.
visited_branches->append(bci);
}
break;
// Check that all switch alternatives end in 'athrow' bytecodes. Since it
// is difficult to determine where each switch alternative ends, parse
// each switch alternative until either hit a 'return', 'athrow', or reach
// the end of the method's bytecodes. This is gross but should be okay
// because:
// 1. tableswitch and lookupswitch byte codes in handlers for ctor explicit
// constructor invocations should be rare.
// 2. if each switch alternative ends in an athrow then the parsing should be
// short. If there is no athrow then it is bogus code, anyway.
case Bytecodes::_lookupswitch:
case Bytecodes::_tableswitch:
{
address aligned_bcp = (address) round_to((intptr_t)(bcs.bcp() + 1), jintSize);
u4 default_offset = Bytes::get_Java_u4(aligned_bcp) + bci;
int keys, delta;
if (opcode == Bytecodes::_tableswitch) {
jint low = (jint)Bytes::get_Java_u4(aligned_bcp + jintSize);
jint high = (jint)Bytes::get_Java_u4(aligned_bcp + 2*jintSize);
// This is invalid, but let the regular bytecode verifier
// report this because the user will get a better error message.
if (low > high) return true;
keys = high - low + 1;
delta = 1;
} else {
keys = (int)Bytes::get_Java_u4(aligned_bcp + jintSize);
delta = 2;
}
// Invalid, let the regular bytecode verifier deal with it.
if (keys < 0) return true;
// Push the offset of the next bytecode onto the stack.
bci_stack->push(bcs.next_bci());
// Push the switch alternatives onto the stack.
for (int i = 0; i < keys; i++) {
u4 target = bci + (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize);
if (target > code_length) return false;
bci_stack->push(target);
}
// Start bytecode parsing for the switch at the default alternative.
if (default_offset > code_length) return false;
bcs.set_start(default_offset);
break;
}
case Bytecodes::_return:
return false;
case Bytecodes::_athrow:
{
if (bci_stack->is_empty()) {
if (handler_stack->is_empty()) {
return true;
} else {
// Parse the catch handlers for try blocks containing athrow.
bcs.set_start(handler_stack->pop());
}
} else {
// Pop a bytecode offset and starting scanning from there.
bcs.set_start(bci_stack->pop());
}
}
break;
default:
;
} // end switch
} // end while loop
return false;
}
void ClassVerifier::verify_invoke_init( void ClassVerifier::verify_invoke_init(
RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type, RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type,
StackMapFrame* current_frame, u4 code_length, bool *this_uninit, StackMapFrame* current_frame, u4 code_length, bool *this_uninit,
...@@ -2250,18 +2425,26 @@ void ClassVerifier::verify_invoke_init( ...@@ -2250,18 +2425,26 @@ void ClassVerifier::verify_invoke_init(
return; return;
} }
// Make sure that this call is not done from within a TRY block because // Check if this call is done from inside of a TRY block. If so, make
// that can result in returning an incomplete object. Simply checking // sure that all catch clause paths end in a throw. Otherwise, this
// (bci >= start_pc) also ensures that this call is not done after a TRY // can result in returning an incomplete object.
// block. That is also illegal because this call must be the first Java
// statement in the constructor.
ExceptionTable exhandlers(_method()); ExceptionTable exhandlers(_method());
int exlength = exhandlers.length(); int exlength = exhandlers.length();
for(int i = 0; i < exlength; i++) { for(int i = 0; i < exlength; i++) {
if (bci >= exhandlers.start_pc(i)) { u2 start_pc = exhandlers.start_pc(i);
verify_error(ErrorContext::bad_code(bci), u2 end_pc = exhandlers.end_pc(i);
"Bad <init> method call from after the start of a try block");
return; 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());
}
} }
} }
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "oops/klass.hpp" #include "oops/klass.hpp"
#include "oops/method.hpp" #include "oops/method.hpp"
#include "runtime/handles.hpp" #include "runtime/handles.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/exceptions.hpp" #include "utilities/exceptions.hpp"
// The verifier class // The verifier class
...@@ -303,6 +304,16 @@ class ClassVerifier : public StackObj { ...@@ -303,6 +304,16 @@ class ClassVerifier : public StackObj {
StackMapFrame* current_frame, u4 code_length, bool* this_uninit, StackMapFrame* current_frame, u4 code_length, bool* this_uninit,
constantPoolHandle cp, TRAPS); constantPoolHandle cp, TRAPS);
// Used by ends_in_athrow() to push all handlers that contain bci onto
// the handler_stack, if the handler is not already on the stack.
void push_handlers(ExceptionTable* exhandlers,
GrowableArray<u4>* handler_stack,
u4 bci);
// Returns true if all paths starting with start_bc_offset end in athrow
// bytecode or loop.
bool ends_in_athrow(u4 start_bc_offset);
void verify_invoke_instructions( void verify_invoke_instructions(
RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame, RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
bool* this_uninit, VerificationType return_type, bool* this_uninit, VerificationType return_type,
......
/* /*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -147,7 +147,8 @@ class VerifyErrorCases { ...@@ -147,7 +147,8 @@ class VerifyErrorCases {
"no stackmap frame at jump location or bad jump", "no stackmap frame at jump location or bad jump",
"Inconsistent stackmap frames at branch target "), "Inconsistent stackmap frames at branch target "),
new Case("case15", "stackMapTable.cpp", true, "check_new_object", /* Backward jump with uninit is allowed starting with JDK 8 */
new Case("case15", "stackMapTable.cpp", false, "check_new_object",
"backward jump with uninit", "backward jump with uninit",
"Uninitialized object exists on backward branch "), "Uninitialized object exists on backward branch "),
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册