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

Merge

......@@ -515,4 +515,5 @@ f3f50c4f9ea5d3af40cb794b6f3f2a337c8873db jdk8u25-b08
9e2bb00a81910776d5b16c49a3f4c5264ceab522 jdk8u25-b11
2993491d47df8c4b096ea7fa534162bde8b53dcf jdk8u25-b12
ca6d25be853b5c428c6228871316671843264666 jdk8u25-b13
c77d5db189422e2eef0443ee212644e497113b18 jdk8u25-b14
5bb683bbe2c74876d585b5c3232fc3aab7b23e97 jdk8u31-b00
......@@ -54,21 +54,6 @@ StackMapFrame* StackMapFrame::frame_in_exception_handler(u1 flags) {
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(
VerificationType old_object, VerificationType new_object) {
int32_t i;
......
......@@ -154,10 +154,6 @@ class StackMapFrame : public ResourceObj {
VerificationType set_locals_from_arg(
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.
// Set every element with type of old_object to new_object.
void initialize_object(
......
......@@ -130,19 +130,6 @@ void StackMapTable::check_jump_target(
if (!match || (target < 0 || target >= _code_length)) {
frame->verifier()->verify_error(ctx,
"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 {
// Returns the frame array index where the frame with offset is stored.
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;
};
......
......@@ -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(
RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type,
StackMapFrame* current_frame, u4 code_length, bool *this_uninit,
......@@ -2250,18 +2425,26 @@ void ClassVerifier::verify_invoke_init(
return;
}
// Make sure that this call is not done from within a TRY block because
// that can result in returning an incomplete object. Simply checking
// (bci >= start_pc) also ensures that this call is not done after a TRY
// block. That is also illegal because this call must be the first Java
// statement in the constructor.
// 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++) {
if (bci >= exhandlers.start_pc(i)) {
verify_error(ErrorContext::bad_code(bci),
"Bad <init> method call from after the start of a try block");
return;
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());
}
}
}
......
......@@ -30,6 +30,7 @@
#include "oops/klass.hpp"
#include "oops/method.hpp"
#include "runtime/handles.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/exceptions.hpp"
// The verifier class
......@@ -303,6 +304,16 @@ class ClassVerifier : public StackObj {
StackMapFrame* current_frame, u4 code_length, bool* this_uninit,
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(
RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -147,7 +147,8 @@ class VerifyErrorCases {
"no stackmap frame at jump location or bad jump",
"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",
"Uninitialized object exists on backward branch "),
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册