7116786: RFE: Detailed information on VerifyErrors
Summary: Provide additional detail in VerifyError messages
Reviewed-by: sspitsyn, acorn
--- a/hotspot/src/os/solaris/vm/dtraceJSDT_solaris.cpp Mon Aug 06 09:34:40 2012 -0700
+++ b/hotspot/src/os/solaris/vm/dtraceJSDT_solaris.cpp Mon Aug 06 15:54:45 2012 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2012, 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
@@ -626,45 +626,6 @@
}
}
-/**
- * This prints out hex data in a 'windbg' or 'xxd' form, where each line is:
- * <hex-address>: 8 * <hex-halfword> <ascii translation>
- * example:
- * 0000000: 7f44 4f46 0102 0102 0000 0000 0000 0000 .DOF............
- * 0000010: 0000 0000 0000 0040 0000 0020 0000 0005 .......@... ....
- * 0000020: 0000 0000 0000 0040 0000 0000 0000 015d .......@.......]
- * ...
- */
-static void printDOFRawData(void* dof) {
- size_t size = ((dof_hdr_t*)dof)->dofh_loadsz;
- size_t limit = (size + 16) / 16 * 16;
- for (size_t i = 0; i < limit; ++i) {
- if (i % 16 == 0) {
- tty->print("%07x:", i);
- }
- if (i % 2 == 0) {
- tty->print(" ");
- }
- if (i < size) {
- tty->print("%02x", ((unsigned char*)dof)[i]);
- } else {
- tty->print(" ");
- }
- if ((i + 1) % 16 == 0) {
- tty->print(" ");
- for (size_t j = 0; j < 16; ++j) {
- size_t idx = i + j - 15;
- char c = ((char*)dof)[idx];
- if (idx < size) {
- tty->print("%c", c >= 32 && c <= 126 ? c : '.');
- }
- }
- tty->print_cr("");
- }
- }
- tty->print_cr("");
-}
-
static void printDOFHelper(dof_helper_t* helper) {
tty->print_cr("// dof_helper_t {");
tty->print_cr("// dofhp_mod = \"%s\"", helper->dofhp_mod);
@@ -672,7 +633,8 @@
tty->print_cr("// dofhp_dof = 0x%016llx", helper->dofhp_dof);
printDOF((void*)helper->dofhp_dof);
tty->print_cr("// }");
- printDOFRawData((void*)helper->dofhp_dof);
+ size_t len = ((dof_hdr_t*)helper)->dofh_loadsz;
+ tty->print_data((void*)helper->dofhp_dof, len, true);
}
#else // ndef HAVE_DTRACE_H
--- a/hotspot/src/share/vm/classfile/stackMapFrame.cpp Mon Aug 06 09:34:40 2012 -0700
+++ b/hotspot/src/share/vm/classfile/stackMapFrame.cpp Mon Aug 06 15:54:45 2012 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, 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
@@ -32,9 +32,9 @@
#include "utilities/globalDefinitions.hpp"
StackMapFrame::StackMapFrame(u2 max_locals, u2 max_stack, ClassVerifier* v) :
- _offset(0), _locals_size(0), _stack_size(0), _flags(0),
- _max_locals(max_locals), _max_stack(max_stack),
- _verifier(v) {
+ _offset(0), _locals_size(0), _stack_size(0),
+ _stack_mark(0), _flags(0), _max_locals(max_locals),
+ _max_stack(max_stack), _verifier(v) {
Thread* thr = v->thread();
_locals = NEW_RESOURCE_ARRAY_IN_THREAD(thr, VerificationType, max_locals);
_stack = NEW_RESOURCE_ARRAY_IN_THREAD(thr, VerificationType, max_stack);
@@ -157,17 +157,17 @@
}
}
-
-bool StackMapFrame::is_assignable_to(
+// Returns the location of the first mismatch, or 'len' if there are no
+// mismatches
+int StackMapFrame::is_assignable_to(
VerificationType* from, VerificationType* to, int32_t len, TRAPS) const {
- for (int32_t i = 0; i < len; i++) {
- bool subtype = to[i].is_assignable_from(
- from[i], verifier(), THREAD);
- if (!subtype) {
- return false;
+ int32_t i = 0;
+ for (i = 0; i < len; i++) {
+ if (!to[i].is_assignable_from(from[i], verifier(), THREAD)) {
+ break;
}
}
- return true;
+ return i;
}
bool StackMapFrame::has_flag_match_exception(
@@ -209,50 +209,84 @@
}
bool StackMapFrame::is_assignable_to(
- const StackMapFrame* target, bool is_exception_handler, TRAPS) const {
- if (_max_locals != target->max_locals() ||
- _stack_size != target->stack_size()) {
+ const StackMapFrame* target, bool is_exception_handler,
+ ErrorContext* ctx, TRAPS) const {
+ if (_max_locals != target->max_locals()) {
+ *ctx = ErrorContext::locals_size_mismatch(
+ _offset, (StackMapFrame*)this, (StackMapFrame*)target);
+ return false;
+ }
+ if (_stack_size != target->stack_size()) {
+ *ctx = ErrorContext::stack_size_mismatch(
+ _offset, (StackMapFrame*)this, (StackMapFrame*)target);
return false;
}
// Only need to compare type elements up to target->locals() or target->stack().
// The remaining type elements in this state can be ignored because they are
// assignable to bogus type.
- bool match_locals = is_assignable_to(
- _locals, target->locals(), target->locals_size(), CHECK_false);
- bool match_stack = is_assignable_to(
- _stack, target->stack(), _stack_size, CHECK_false);
+ int mismatch_loc;
+ mismatch_loc = is_assignable_to(
+ _locals, target->locals(), target->locals_size(), THREAD);
+ if (mismatch_loc != target->locals_size()) {
+ *ctx = ErrorContext::bad_type(target->offset(),
+ TypeOrigin::local(mismatch_loc, (StackMapFrame*)this),
+ TypeOrigin::sm_local(mismatch_loc, (StackMapFrame*)target));
+ return false;
+ }
+ mismatch_loc = is_assignable_to(_stack, target->stack(), _stack_size, THREAD);
+ if (mismatch_loc != _stack_size) {
+ *ctx = ErrorContext::bad_type(target->offset(),
+ TypeOrigin::stack(mismatch_loc, (StackMapFrame*)this),
+ TypeOrigin::sm_stack(mismatch_loc, (StackMapFrame*)target));
+ return false;
+ }
+
bool match_flags = (_flags | target->flags()) == target->flags();
-
- return match_locals && match_stack &&
- (match_flags || (is_exception_handler && has_flag_match_exception(target)));
+ if (match_flags || is_exception_handler && has_flag_match_exception(target)) {
+ return true;
+ } else {
+ *ctx = ErrorContext::bad_flags(target->offset(),
+ (StackMapFrame*)this, (StackMapFrame*)target);
+ return false;
+ }
}
VerificationType StackMapFrame::pop_stack_ex(VerificationType type, TRAPS) {
if (_stack_size <= 0) {
- verifier()->verify_error(_offset, "Operand stack underflow");
+ verifier()->verify_error(
+ ErrorContext::stack_underflow(_offset, this),
+ "Operand stack underflow");
return VerificationType::bogus_type();
}
VerificationType top = _stack[--_stack_size];
bool subtype = type.is_assignable_from(
top, verifier(), CHECK_(VerificationType::bogus_type()));
if (!subtype) {
- verifier()->verify_error(_offset, "Bad type on operand stack");
+ verifier()->verify_error(
+ ErrorContext::bad_type(_offset, stack_top_ctx(),
+ TypeOrigin::implicit(type)),
+ "Bad type on operand stack");
return VerificationType::bogus_type();
}
- NOT_PRODUCT( _stack[_stack_size] = VerificationType::bogus_type(); )
return top;
}
VerificationType StackMapFrame::get_local(
int32_t index, VerificationType type, TRAPS) {
if (index >= _max_locals) {
- verifier()->verify_error(_offset, "Local variable table overflow");
+ verifier()->verify_error(
+ ErrorContext::bad_local_index(_offset, index),
+ "Local variable table overflow");
return VerificationType::bogus_type();
}
bool subtype = type.is_assignable_from(_locals[index],
verifier(), CHECK_(VerificationType::bogus_type()));
if (!subtype) {
- verifier()->verify_error(_offset, "Bad local variable type");
+ verifier()->verify_error(
+ ErrorContext::bad_type(_offset,
+ TypeOrigin::local(index, this),
+ TypeOrigin::implicit(type)),
+ "Bad local variable type");
return VerificationType::bogus_type();
}
if(index >= _locals_size) { _locals_size = index + 1; }
@@ -264,23 +298,37 @@
assert(type1.is_long() || type1.is_double(), "must be long/double");
assert(type2.is_long2() || type2.is_double2(), "must be long/double_2");
if (index >= _locals_size - 1) {
- verifier()->verify_error(_offset, "get long/double overflows locals");
+ verifier()->verify_error(
+ ErrorContext::bad_local_index(_offset, index),
+ "get long/double overflows locals");
return;
}
- bool subtype1 = type1.is_assignable_from(
- _locals[index], verifier(), CHECK);
- bool subtype2 = type2.is_assignable_from(
- _locals[index+1], verifier(), CHECK);
- if (!subtype1 || !subtype2) {
- verifier()->verify_error(_offset, "Bad local variable type");
- return;
+ bool subtype = type1.is_assignable_from(_locals[index], verifier(), CHECK);
+ if (!subtype) {
+ verifier()->verify_error(
+ ErrorContext::bad_type(_offset,
+ TypeOrigin::local(index, this), TypeOrigin::implicit(type1)),
+ "Bad local variable type");
+ } else {
+ subtype = type2.is_assignable_from(_locals[index + 1], verifier(), CHECK);
+ if (!subtype) {
+ /* Unreachable? All local store routines convert a split long or double
+ * into a TOP during the store. So we should never end up seeing an
+ * orphaned half. */
+ verifier()->verify_error(
+ ErrorContext::bad_type(_offset,
+ TypeOrigin::local(index + 1, this), TypeOrigin::implicit(type2)),
+ "Bad local variable type");
+ }
}
}
void StackMapFrame::set_local(int32_t index, VerificationType type, TRAPS) {
assert(!type.is_check(), "Must be a real type");
if (index >= _max_locals) {
- verifier()->verify_error("Local variable table overflow", _offset);
+ verifier()->verify_error(
+ ErrorContext::bad_local_index(_offset, index),
+ "Local variable table overflow");
return;
}
// If type at index is double or long, set the next location to be unusable
@@ -310,7 +358,9 @@
assert(type1.is_long() || type1.is_double(), "must be long/double");
assert(type2.is_long2() || type2.is_double2(), "must be long/double_2");
if (index >= _max_locals - 1) {
- verifier()->verify_error("Local variable table overflow", _offset);
+ verifier()->verify_error(
+ ErrorContext::bad_local_index(_offset, index),
+ "Local variable table overflow");
return;
}
// If type at index+1 is double or long, set the next location to be unusable
@@ -336,21 +386,30 @@
}
}
-#ifndef PRODUCT
-
-void StackMapFrame::print() const {
- tty->print_cr("stackmap_frame[%d]:", _offset);
- tty->print_cr("flags = 0x%x", _flags);
- tty->print("locals[%d] = { ", _locals_size);
- for (int32_t i = 0; i < _locals_size; i++) {
- _locals[i].print_on(tty);
- }
- tty->print_cr(" }");
- tty->print("stack[%d] = { ", _stack_size);
- for (int32_t j = 0; j < _stack_size; j++) {
- _stack[j].print_on(tty);
- }
- tty->print_cr(" }");
+TypeOrigin StackMapFrame::stack_top_ctx() {
+ return TypeOrigin::stack(_stack_size, this);
}
-#endif
+void StackMapFrame::print_on(outputStream* str) const {
+ str->indent().print_cr("bci: @%d", _offset);
+ str->indent().print_cr("flags: {%s }",
+ flag_this_uninit() ? " flagThisUninit" : "");
+ str->indent().print("locals: {");
+ for (int32_t i = 0; i < _locals_size; ++i) {
+ str->print(" ");
+ _locals[i].print_on(str);
+ if (i != _locals_size - 1) {
+ str->print(",");
+ }
+ }
+ str->print_cr(" }");
+ str->indent().print("stack: {");
+ for (int32_t j = 0; j < _stack_size; ++j) {
+ str->print(" ");
+ _stack[j].print_on(str);
+ if (j != _stack_size - 1) {
+ str->print(",");
+ }
+ }
+ str->print_cr(" }");
+}
--- a/hotspot/src/share/vm/classfile/stackMapFrame.hpp Mon Aug 06 09:34:40 2012 -0700
+++ b/hotspot/src/share/vm/classfile/stackMapFrame.hpp Mon Aug 06 15:54:45 2012 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, 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
@@ -34,6 +34,8 @@
// A StackMapFrame represents one frame in the stack map attribute.
+class TypeContext;
+
enum {
FLAG_THIS_UNINIT = 0x01
};
@@ -47,6 +49,10 @@
int32_t _locals_size; // number of valid type elements in _locals
int32_t _stack_size; // number of valid type elements in _stack
+ int32_t _stack_mark; // Records the size of the stack prior to an
+ // instruction modification, to allow rewinding
+ // when/if an error occurs.
+
int32_t _max_locals;
int32_t _max_stack;
@@ -56,6 +62,31 @@
ClassVerifier* _verifier; // the verifier verifying this method
+ StackMapFrame(const StackMapFrame& cp) :
+ _offset(cp._offset), _locals_size(cp._locals_size),
+ _stack_size(cp._stack_size), _stack_mark(cp._stack_mark),
+ _max_locals(cp._max_locals), _max_stack(cp._max_stack),
+ _flags(cp._flags) {
+ _locals = NEW_RESOURCE_ARRAY(VerificationType, _max_locals);
+ for (int i = 0; i < _max_locals; ++i) {
+ if (i < _locals_size) {
+ _locals[i] = cp._locals[i];
+ } else {
+ _locals[i] = VerificationType::bogus_type();
+ }
+ }
+ int ss = MAX2(_stack_size, _stack_mark);
+ _stack = NEW_RESOURCE_ARRAY(VerificationType, _max_stack);
+ for (int i = 0; i < _max_stack; ++i) {
+ if (i < ss) {
+ _stack[i] = cp._stack[i];
+ } else {
+ _stack[i] = VerificationType::bogus_type();
+ }
+ }
+ _verifier = NULL;
+ }
+
public:
// constructors
@@ -77,16 +108,21 @@
ClassVerifier* v) : _offset(offset), _flags(flags),
_locals_size(locals_size),
_stack_size(stack_size),
+ _stack_mark(-1),
_max_locals(max_locals),
_max_stack(max_stack),
_locals(locals), _stack(stack),
_verifier(v) { }
+ static StackMapFrame* copy(StackMapFrame* smf) {
+ return new StackMapFrame(*smf);
+ }
+
inline void set_offset(int32_t offset) { _offset = offset; }
inline void set_verifier(ClassVerifier* v) { _verifier = v; }
inline void set_flags(u1 flags) { _flags = flags; }
inline void set_locals_size(u2 locals_size) { _locals_size = locals_size; }
- inline void set_stack_size(u2 stack_size) { _stack_size = stack_size; }
+ inline void set_stack_size(u2 stack_size) { _stack_size = _stack_mark = stack_size; }
inline void clear_stack() { _stack_size = 0; }
inline int32_t offset() const { return _offset; }
inline ClassVerifier* verifier() const { return _verifier; }
@@ -134,14 +170,37 @@
void copy_stack(const StackMapFrame* src);
// Return true if this stack map frame is assignable to target.
- bool is_assignable_to(const StackMapFrame* target,
- bool is_exception_handler, TRAPS) const;
+ bool is_assignable_to(
+ const StackMapFrame* target, bool is_exception_handler,
+ ErrorContext* ctx, TRAPS) const;
+
+ inline void set_mark() {
+#ifdef DEBUG
+ // Put bogus type to indicate it's no longer valid.
+ if (_stack_mark != -1) {
+ for (int i = _stack_mark; i >= _stack_size; --i) {
+ _stack[i] = VerificationType::bogus_type();
+ }
+ }
+#endif // def DEBUG
+ _stack_mark = _stack_size;
+ }
+
+ // Used when an error occurs and we want to reset the stack to the state
+ // it was before operands were popped off.
+ void restore() {
+ if (_stack_mark != -1) {
+ _stack_size = _stack_mark;
+ }
+ }
// Push type into stack type array.
inline void push_stack(VerificationType type, TRAPS) {
assert(!type.is_check(), "Must be a real type");
if (_stack_size >= _max_stack) {
- verifier()->verify_error(_offset, "Operand stack overflow");
+ verifier()->verify_error(
+ ErrorContext::stack_overflow(_offset, this),
+ "Operand stack overflow");
return;
}
_stack[_stack_size++] = type;
@@ -152,7 +211,9 @@
assert(type1.is_long() || type1.is_double(), "must be long/double");
assert(type2.is_long2() || type2.is_double2(), "must be long/double_2");
if (_stack_size >= _max_stack - 1) {
- verifier()->verify_error(_offset, "Operand stack overflow");
+ verifier()->verify_error(
+ ErrorContext::stack_overflow(_offset, this),
+ "Operand stack overflow");
return;
}
_stack[_stack_size++] = type1;
@@ -162,13 +223,12 @@
// Pop and return the top type on stack without verifying.
inline VerificationType pop_stack(TRAPS) {
if (_stack_size <= 0) {
- verifier()->verify_error(_offset, "Operand stack underflow");
+ verifier()->verify_error(
+ ErrorContext::stack_underflow(_offset, this),
+ "Operand stack underflow");
return VerificationType::bogus_type();
}
- // Put bogus type to indicate it's no longer valid.
- // Added to make it consistent with the other pop_stack method.
VerificationType top = _stack[--_stack_size];
- NOT_PRODUCT( _stack[_stack_size] = VerificationType::bogus_type(); )
return top;
}
@@ -180,8 +240,7 @@
bool subtype = type.is_assignable_from(
top, verifier(), CHECK_(VerificationType::bogus_type()));
if (subtype) {
- _stack_size --;
- NOT_PRODUCT( _stack[_stack_size] = VerificationType::bogus_type(); )
+ --_stack_size;
return top;
}
}
@@ -199,8 +258,6 @@
bool subtype2 = type2.is_assignable_from(top2, verifier(), CHECK);
if (subtype1 && subtype2) {
_stack_size -= 2;
- NOT_PRODUCT( _stack[_stack_size] = VerificationType::bogus_type(); )
- NOT_PRODUCT( _stack[_stack_size+1] = VerificationType::bogus_type(); )
return;
}
}
@@ -208,6 +265,14 @@
pop_stack_ex(type2, THREAD);
}
+ VerificationType local_at(int index) {
+ return _locals[index];
+ }
+
+ VerificationType stack_at(int index) {
+ return _stack[index];
+ }
+
// Uncommon case that throws exceptions.
VerificationType pop_stack_ex(VerificationType type, TRAPS);
@@ -226,13 +291,14 @@
// Private auxiliary method used only in is_assignable_to(StackMapFrame).
// Returns true if src is assignable to target.
- bool is_assignable_to(
+ int is_assignable_to(
VerificationType* src, VerificationType* target, int32_t len, TRAPS) const;
bool has_flag_match_exception(const StackMapFrame* target) const;
- // Debugging
- void print() const PRODUCT_RETURN;
+ TypeOrigin stack_top_ctx();
+
+ void print_on(outputStream* str) const;
};
#endif // SHARE_VM_CLASSFILE_STACKMAPFRAME_HPP
--- a/hotspot/src/share/vm/classfile/stackMapTable.cpp Mon Aug 06 09:34:40 2012 -0700
+++ b/hotspot/src/share/vm/classfile/stackMapTable.cpp Mon Aug 06 15:54:45 2012 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, 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
@@ -46,7 +46,9 @@
_frame_array[i] = frame;
int offset = frame->offset();
if (offset >= code_len || code_data[offset] == 0) {
- frame->verifier()->verify_error("StackMapTable error: bad offset");
+ frame->verifier()->verify_error(
+ ErrorContext::bad_stackmap(i, frame),
+ "StackMapTable error: bad offset");
return;
}
pre_frame = frame;
@@ -68,12 +70,9 @@
bool StackMapTable::match_stackmap(
StackMapFrame* frame, int32_t target,
- bool match, bool update, TRAPS) const {
+ bool match, bool update, ErrorContext* ctx, TRAPS) const {
int index = get_index_from_offset(target);
-
- return match_stackmap(
- frame, target, index, match,
- update, CHECK_VERIFY_(frame->verifier(), false));
+ return match_stackmap(frame, target, index, match, update, ctx, THREAD);
}
// Match and/or update current_frame to the frame in stackmap table with
@@ -88,23 +87,23 @@
// unconditional branch: true true
bool StackMapTable::match_stackmap(
StackMapFrame* frame, int32_t target, int32_t frame_index,
- bool match, bool update, TRAPS) const {
+ bool match, bool update, ErrorContext* ctx, TRAPS) const {
if (frame_index < 0 || frame_index >= _frame_count) {
- frame->verifier()->verify_error(frame->offset(),
- "Expecting a stackmap frame at branch target %d", target);
+ *ctx = ErrorContext::missing_stackmap(frame->offset());
+ frame->verifier()->verify_error(
+ *ctx, "Expecting a stackmap frame at branch target %d", target);
return false;
}
+ StackMapFrame *stackmap_frame = _frame_array[frame_index];
bool result = true;
- StackMapFrame *stackmap_frame = _frame_array[frame_index];
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
// frames.
- result = frame->is_assignable_to(
- stackmap_frame, is_exception_handler,
- CHECK_VERIFY_(frame->verifier(), false));
+ result = frame->is_assignable_to(stackmap_frame, is_exception_handler,
+ ctx, CHECK_VERIFY_(frame->verifier(), result));
}
if (update) {
// Use the frame in stackmap table as current frame
@@ -125,11 +124,12 @@
void StackMapTable::check_jump_target(
StackMapFrame* frame, int32_t target, TRAPS) const {
+ ErrorContext ctx;
bool match = match_stackmap(
- frame, target, true, false, CHECK_VERIFY(frame->verifier()));
+ frame, target, true, false, &ctx, CHECK_VERIFY(frame->verifier()));
if (!match || (target < 0 || target >= _code_length)) {
- frame->verifier()->verify_error(frame->offset(),
- "Inconsistent stackmap frames at branch target %d", target);
+ frame->verifier()->verify_error(ctx,
+ "Inconsistent stackmap frames at branch target %d", target);
return;
}
// check if uninitialized objects exist on backward branches
@@ -139,25 +139,25 @@
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(frame->offset(),
- "Uninitialized object exists on backward branch %d", target);
+ frame->verifier()->verify_error(
+ ErrorContext::bad_code(frame->offset()),
+ "Uninitialized object exists on backward branch %d", target);
return;
}
}
-#ifndef PRODUCT
-
-void StackMapTable::print() const {
- tty->print_cr("StackMapTable: frame_count = %d", _frame_count);
- tty->print_cr("table = { ");
- for (int32_t i = 0; i < _frame_count; i++) {
- _frame_array[i]->print();
+void StackMapTable::print_on(outputStream* str) const {
+ str->indent().print_cr("StackMapTable: frame_count = %d", _frame_count);
+ str->indent().print_cr("table = { ");
+ {
+ streamIndentor si(str);
+ for (int32_t i = 0; i < _frame_count; ++i) {
+ _frame_array[i]->print_on(str);
+ }
}
- tty->print_cr(" }");
+ str->print_cr(" }");
}
-#endif
-
int32_t StackMapReader::chop(
VerificationType* locals, int32_t length, int32_t chops) {
if (locals == NULL) return -1;
--- a/hotspot/src/share/vm/classfile/stackMapTable.hpp Mon Aug 06 09:34:40 2012 -0700
+++ b/hotspot/src/share/vm/classfile/stackMapTable.hpp Mon Aug 06 15:54:45 2012 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, 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
@@ -26,6 +26,7 @@
#define SHARE_VM_CLASSFILE_STACKMAPTABLE_HPP
#include "classfile/stackMapFrame.hpp"
+#include "classfile/verifier.hpp"
#include "memory/allocation.hpp"
#include "oops/constantPoolOop.hpp"
#include "oops/methodOop.hpp"
@@ -73,12 +74,12 @@
// specified offset. Return true if the two frames match.
bool match_stackmap(
StackMapFrame* current_frame, int32_t offset,
- bool match, bool update, TRAPS) const;
+ bool match, bool update, ErrorContext* ctx, TRAPS) const;
// 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.
bool match_stackmap(
StackMapFrame* current_frame, int32_t offset, int32_t frame_index,
- bool match, bool update, TRAPS) const;
+ bool match, bool update, ErrorContext* ctx, TRAPS) const;
// Check jump instructions. Make sure there are no uninitialized
// instances on backward branch.
@@ -93,8 +94,7 @@
void check_new_object(
const StackMapFrame* frame, int32_t target, TRAPS) const;
- // Debugging
- void print() const PRODUCT_RETURN;
+ void print_on(outputStream* str) const;
};
class StackMapStream : StackObj {
--- a/hotspot/src/share/vm/classfile/stackMapTableFormat.hpp Mon Aug 06 09:34:40 2012 -0700
+++ b/hotspot/src/share/vm/classfile/stackMapTableFormat.hpp Mon Aug 06 15:54:45 2012 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2012, 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
@@ -135,7 +135,6 @@
!is_object() && !is_uninitialized()));
}
-#ifdef ASSERT
void print_on(outputStream* st) {
switch (tag()) {
case ITEM_Top: st->print("Top"); break;
@@ -154,14 +153,13 @@
assert(false, "Bad verification_type_info");
}
}
-#endif
};
#define FOR_EACH_STACKMAP_FRAME_TYPE(macro, arg1, arg2) \
macro(same_frame, arg1, arg2) \
macro(same_frame_extended, arg1, arg2) \
- macro(same_frame_1_stack_item_frame, arg1, arg2) \
- macro(same_frame_1_stack_item_extended, arg1, arg2) \
+ macro(same_locals_1_stack_item_frame, arg1, arg2) \
+ macro(same_locals_1_stack_item_extended, arg1, arg2) \
macro(chop_frame, arg1, arg2) \
macro(append_frame, arg1, arg2) \
macro(full_frame, arg1, arg2)
@@ -203,9 +201,8 @@
// that we don't read past a particular memory limit. It returns false
// if any part of the data structure is outside the specified memory bounds.
inline bool verify(address start, address end) const;
-#ifdef ASSERT
- inline void print_on(outputStream* st) const;
-#endif
+
+ inline void print_on(outputStream* st, int current_offset) const;
// Create as_xxx and is_xxx methods for the subtypes
#define FRAME_TYPE_DECL(stackmap_frame_type, arg1, arg2) \
@@ -263,11 +260,9 @@
return true;
}
-#ifdef ASSERT
- void print_on(outputStream* st) const {
- st->print("same_frame(%d)", offset_delta());
+ void print_on(outputStream* st, int current_offset = -1) const {
+ st->print("same_frame(@%d)", offset_delta() + current_offset);
}
-#endif
};
class same_frame_extended : public stack_map_frame {
@@ -311,14 +306,12 @@
return frame_type_addr() + size() <= end;
}
-#ifdef ASSERT
- void print_on(outputStream* st) const {
- st->print("same_frame_extended(%d)", offset_delta());
+ void print_on(outputStream* st, int current_offset = -1) const {
+ st->print("same_frame_extended(@%d)", offset_delta() + current_offset);
}
-#endif
};
-class same_frame_1_stack_item_frame : public stack_map_frame {
+class same_locals_1_stack_item_frame : public stack_map_frame {
private:
address type_addr() const { return frame_type_addr() + sizeof(u1); }
@@ -332,14 +325,14 @@
return tag >= 64 && tag < 128;
}
- static same_frame_1_stack_item_frame* at(address addr) {
+ static same_locals_1_stack_item_frame* at(address addr) {
assert(is_frame_type(*addr), "Wrong frame id");
- return (same_frame_1_stack_item_frame*)addr;
+ return (same_locals_1_stack_item_frame*)addr;
}
- static same_frame_1_stack_item_frame* create_at(
+ static same_locals_1_stack_item_frame* create_at(
address addr, int offset_delta, verification_type_info* vti) {
- same_frame_1_stack_item_frame* sm = (same_frame_1_stack_item_frame*)addr;
+ same_locals_1_stack_item_frame* sm = (same_locals_1_stack_item_frame*)addr;
sm->set_offset_delta(offset_delta);
if (vti != NULL) {
sm->set_type(vti);
@@ -382,16 +375,15 @@
return types()->verify(start, end);
}
-#ifdef ASSERT
- void print_on(outputStream* st) const {
- st->print("same_frame_1_stack_item_frame(%d,", offset_delta());
+ void print_on(outputStream* st, int current_offset = -1) const {
+ st->print("same_locals_1_stack_item_frame(@%d,",
+ offset_delta() + current_offset);
types()->print_on(st);
st->print(")");
}
-#endif
};
-class same_frame_1_stack_item_extended : public stack_map_frame {
+class same_locals_1_stack_item_extended : public stack_map_frame {
private:
address offset_delta_addr() const { return frame_type_addr() + sizeof(u1); }
address type_addr() const { return offset_delta_addr() + sizeof(u2); }
@@ -403,15 +395,15 @@
return tag == _frame_id;
}
- static same_frame_1_stack_item_extended* at(address addr) {
+ static same_locals_1_stack_item_extended* at(address addr) {
assert(is_frame_type(*addr), "Wrong frame id");
- return (same_frame_1_stack_item_extended*)addr;
+ return (same_locals_1_stack_item_extended*)addr;
}
- static same_frame_1_stack_item_extended* create_at(
+ static same_locals_1_stack_item_extended* create_at(
address addr, int offset_delta, verification_type_info* vti) {
- same_frame_1_stack_item_extended* sm =
- (same_frame_1_stack_item_extended*)addr;
+ same_locals_1_stack_item_extended* sm =
+ (same_locals_1_stack_item_extended*)addr;
sm->set_frame_type(_frame_id);
sm->set_offset_delta(offset_delta);
if (vti != NULL) {
@@ -448,13 +440,12 @@
return type_addr() < end && types()->verify(start, end);
}
-#ifdef ASSERT
- void print_on(outputStream* st) const {
- st->print("same_frame_1_stack_item_extended(%d,", offset_delta());
+ void print_on(outputStream* st, int current_offset = -1) const {
+ st->print("same_locals_1_stack_item_extended(@%d,",
+ offset_delta() + current_offset);
types()->print_on(st);
st->print(")");
}
-#endif
};
class chop_frame : public stack_map_frame {
@@ -517,11 +508,9 @@
return frame_type_addr() + size() <= end;
}
-#ifdef ASSERT
- void print_on(outputStream* st) const {
- st->print("chop_frame(%d,%d)", offset_delta(), chops());
+ void print_on(outputStream* st, int current_offset = -1) const {
+ st->print("chop_frame(@%d,%d)", offset_delta() + current_offset, chops());
}
-#endif
};
class append_frame : public stack_map_frame {
@@ -618,9 +607,8 @@
return false;
}
-#ifdef ASSERT
- void print_on(outputStream* st) const {
- st->print("append_frame(%d,", offset_delta());
+ void print_on(outputStream* st, int current_offset = -1) const {
+ st->print("append_frame(@%d,", offset_delta() + current_offset);
verification_type_info* vti = types();
for (int i = 0; i < number_of_types(); ++i) {
vti->print_on(st);
@@ -631,7 +619,6 @@
}
st->print(")");
}
-#endif
};
class full_frame : public stack_map_frame {
@@ -774,9 +761,8 @@
return true;
}
-#ifdef ASSERT
- void print_on(outputStream* st) const {
- st->print("full_frame(%d,{", offset_delta());
+ void print_on(outputStream* st, int current_offset = -1) const {
+ st->print("full_frame(@%d,{", offset_delta() + current_offset);
verification_type_info* vti = locals();
for (int i = 0; i < num_locals(); ++i) {
vti->print_on(st);
@@ -798,7 +784,6 @@
}
st->print("})");
}
-#endif
};
#define VIRTUAL_DISPATCH(stack_frame_type, func_name, args) \
@@ -852,11 +837,9 @@
return false;
}
-#ifdef ASSERT
-void stack_map_frame::print_on(outputStream* st) const {
- FOR_EACH_STACKMAP_FRAME_TYPE(VOID_VIRTUAL_DISPATCH, print_on, (st));
+void stack_map_frame::print_on(outputStream* st, int offs = -1) const {
+ FOR_EACH_STACKMAP_FRAME_TYPE(VOID_VIRTUAL_DISPATCH, print_on, (st, offs));
}
-#endif
#undef VIRTUAL_DISPATCH
#undef VOID_VIRTUAL_DISPATCH
@@ -873,16 +856,46 @@
FOR_EACH_STACKMAP_FRAME_TYPE(AS_SUBTYPE_DEF, x, x)
#undef AS_SUBTYPE_DEF
+class stack_map_table {
+ private:
+ address number_of_entries_addr() const {
+ return (address)this;
+ }
+ address entries_addr() const {
+ return number_of_entries_addr() + sizeof(u2);
+ }
+
+ protected:
+ // No constructors - should be 'private', but GCC issues a warning if it is
+ stack_map_table() {}
+ stack_map_table(const stack_map_table&) {}
+
+ public:
+
+ static stack_map_table* at(address addr) {
+ return (stack_map_table*)addr;
+ }
+
+ u2 number_of_entries() const {
+ return Bytes::get_Java_u2(number_of_entries_addr());
+ }
+ stack_map_frame* entries() const {
+ return stack_map_frame::at(entries_addr());
+ }
+
+ void set_number_of_entries(u2 num) {
+ Bytes::put_Java_u2(number_of_entries_addr(), num);
+ }
+};
+
class stack_map_table_attribute {
private:
address name_index_addr() const {
return (address)this; }
address attribute_length_addr() const {
return name_index_addr() + sizeof(u2); }
- address number_of_entries_addr() const {
+ address stack_map_table_addr() const {
return attribute_length_addr() + sizeof(u4); }
- address entries_addr() const {
- return number_of_entries_addr() + sizeof(u2); }
protected:
// No constructors - should be 'private', but GCC issues a warning if it is
@@ -896,17 +909,11 @@
}
u2 name_index() const {
- return Bytes::get_Java_u2(name_index_addr()); }
+ return Bytes::get_Java_u2(name_index_addr()); }
u4 attribute_length() const {
- return Bytes::get_Java_u4(attribute_length_addr()); }
- u2 number_of_entries() const {
- return Bytes::get_Java_u2(number_of_entries_addr()); }
- stack_map_frame* entries() const {
- return stack_map_frame::at(entries_addr());
- }
-
- static size_t header_size() {
- return sizeof(u2) + sizeof(u4);
+ return Bytes::get_Java_u4(attribute_length_addr()); }
+ stack_map_table* table() const {
+ return stack_map_table::at(stack_map_table_addr());
}
void set_name_index(u2 idx) {
@@ -915,9 +922,8 @@
void set_attribute_length(u4 len) {
Bytes::put_Java_u4(attribute_length_addr(), len);
}
- void set_number_of_entries(u2 num) {
- Bytes::put_Java_u2(number_of_entries_addr(), num);
- }
};
+#undef FOR_EACH_STACKMAP_FRAME_TYPE
+
#endif // SHARE_VM_CLASSFILE_STACKMAPTABLEFORMAT_HPP
--- a/hotspot/src/share/vm/classfile/verificationType.cpp Mon Aug 06 09:34:40 2012 -0700
+++ b/hotspot/src/share/vm/classfile/verificationType.cpp Mon Aug 06 15:54:45 2012 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, 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
@@ -110,34 +110,34 @@
}
}
-#ifndef PRODUCT
-
void VerificationType::print_on(outputStream* st) const {
switch (_u._data) {
- case Bogus: st->print(" bogus "); break;
- case Category1: st->print(" category1 "); break;
- case Category2: st->print(" category2 "); break;
- case Category2_2nd: st->print(" category2_2nd "); break;
- case Boolean: st->print(" boolean "); break;
- case Byte: st->print(" byte "); break;
- case Short: st->print(" short "); break;
- case Char: st->print(" char "); break;
- case Integer: st->print(" integer "); break;
- case Float: st->print(" float "); break;
- case Long: st->print(" long "); break;
- case Double: st->print(" double "); break;
- case Long_2nd: st->print(" long_2nd "); break;
- case Double_2nd: st->print(" double_2nd "); break;
- case Null: st->print(" null "); break;
+ case Bogus: st->print("top"); break;
+ case Category1: st->print("category1"); break;
+ case Category2: st->print("category2"); break;
+ case Category2_2nd: st->print("category2_2nd"); break;
+ case Boolean: st->print("boolean"); break;
+ case Byte: st->print("byte"); break;
+ case Short: st->print("short"); break;
+ case Char: st->print("char"); break;
+ case Integer: st->print("integer"); break;
+ case Float: st->print("float"); break;
+ case Long: st->print("long"); break;
+ case Double: st->print("double"); break;
+ case Long_2nd: st->print("long_2nd"); break;
+ case Double_2nd: st->print("double_2nd"); break;
+ case Null: st->print("null"); break;
+ case ReferenceQuery: st->print("reference type"); break;
+ case Category1Query: st->print("category1 type"); break;
+ case Category2Query: st->print("category2 type"); break;
+ case Category2_2ndQuery: st->print("category2_2nd type"); break;
default:
if (is_uninitialized_this()) {
- st->print(" uninitializedThis ");
+ st->print("uninitializedThis");
} else if (is_uninitialized()) {
- st->print(" uninitialized %d ", bci());
+ st->print("uninitialized %d", bci());
} else {
- st->print(" class %s ", name()->as_klass_external_name());
+ name()->print_value_on(st);
}
}
}
-
-#endif
--- a/hotspot/src/share/vm/classfile/verificationType.hpp Mon Aug 06 09:34:40 2012 -0700
+++ b/hotspot/src/share/vm/classfile/verificationType.hpp Mon Aug 06 15:54:45 2012 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, 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
@@ -157,7 +157,7 @@
// For reference types, store the actual Symbol
static VerificationType reference_type(Symbol* sh) {
- assert(((uintptr_t)sh & 0x3) == 0, "Oops must be aligned");
+ assert(((uintptr_t)sh & 0x3) == 0, "Symbols must be aligned");
// If the above assert fails in the future because oop* isn't aligned,
// then this type encoding system will have to change to have a tag value
// to descriminate between oops and primitives.
@@ -303,7 +303,7 @@
return index;
}
- void print_on(outputStream* st) const PRODUCT_RETURN;
+ void print_on(outputStream* st) const;
private:
--- a/hotspot/src/share/vm/classfile/verifier.cpp Mon Aug 06 09:34:40 2012 -0700
+++ b/hotspot/src/share/vm/classfile/verifier.cpp Mon Aug 06 15:54:45 2012 -0400
@@ -26,9 +26,12 @@
#include "classfile/classFileStream.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/stackMapTable.hpp"
+#include "classfile/stackMapFrame.hpp"
+#include "classfile/stackMapTableFormat.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/verifier.hpp"
#include "classfile/vmSymbols.hpp"
+#include "interpreter/bytecodes.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
@@ -110,8 +113,11 @@
Symbol* exception_name = NULL;
const size_t message_buffer_len = klass->name()->utf8_length() + 1024;
char* message_buffer = NEW_RESOURCE_ARRAY(char, message_buffer_len);
+ char* exception_message = message_buffer;
const char* klassName = klass->external_name();
+ bool can_failover = FailOverToOldVerifier &&
+ klass->major_version() < NOFAILOVER_MAJOR_VERSION;
// If the class should be verified, first see if we can use the split
// verifier. If not, or if verification fails and FailOverToOldVerifier
@@ -122,27 +128,28 @@
}
if (UseSplitVerifier &&
klass->major_version() >= STACKMAP_ATTRIBUTE_MAJOR_VERSION) {
- ClassVerifier split_verifier(
- klass, message_buffer, message_buffer_len, THREAD);
- split_verifier.verify_class(THREAD);
- exception_name = split_verifier.result();
- if (klass->major_version() < NOFAILOVER_MAJOR_VERSION &&
- FailOverToOldVerifier && !HAS_PENDING_EXCEPTION &&
+ ClassVerifier split_verifier(klass, THREAD);
+ split_verifier.verify_class(THREAD);
+ exception_name = split_verifier.result();
+ if (can_failover && !HAS_PENDING_EXCEPTION &&
(exception_name == vmSymbols::java_lang_VerifyError() ||
exception_name == vmSymbols::java_lang_ClassFormatError())) {
- if (TraceClassInitialization) {
+ if (TraceClassInitialization || VerboseVerification) {
tty->print_cr(
"Fail over class verification to old verifier for: %s", klassName);
}
exception_name = inference_verify(
klass, message_buffer, message_buffer_len, THREAD);
}
+ if (exception_name != NULL) {
+ exception_message = split_verifier.exception_message();
+ }
} else {
exception_name = inference_verify(
klass, message_buffer, message_buffer_len, THREAD);
}
- if (TraceClassInitialization) {
+ if (TraceClassInitialization || VerboseVerification) {
if (HAS_PENDING_EXCEPTION) {
tty->print("Verification for %s has", klassName);
tty->print_cr(" exception pending %s ",
@@ -173,7 +180,7 @@
kls = kls->super();
}
message_buffer[message_buffer_len - 1] = '\0'; // just to be sure
- THROW_MSG_(exception_name, message_buffer, false);
+ THROW_MSG_(exception_name, exception_message, false);
}
}
@@ -221,7 +228,7 @@
}
ResourceMark rm(THREAD);
- if (ClassVerifier::_verify_verbose) {
+ if (VerboseVerification) {
tty->print_cr("Verifying class %s with old format", klass->external_name());
}
@@ -265,14 +272,252 @@
}
}
+TypeOrigin TypeOrigin::null() {
+ return TypeOrigin();
+}
+TypeOrigin TypeOrigin::local(u2 index, StackMapFrame* frame) {
+ assert(frame != NULL, "Must have a frame");
+ return TypeOrigin(CF_LOCALS, index, StackMapFrame::copy(frame),
+ frame->local_at(index));
+}
+TypeOrigin TypeOrigin::stack(u2 index, StackMapFrame* frame) {
+ assert(frame != NULL, "Must have a frame");
+ return TypeOrigin(CF_STACK, index, StackMapFrame::copy(frame),
+ frame->stack_at(index));
+}
+TypeOrigin TypeOrigin::sm_local(u2 index, StackMapFrame* frame) {
+ assert(frame != NULL, "Must have a frame");
+ return TypeOrigin(SM_LOCALS, index, StackMapFrame::copy(frame),
+ frame->local_at(index));
+}
+TypeOrigin TypeOrigin::sm_stack(u2 index, StackMapFrame* frame) {
+ assert(frame != NULL, "Must have a frame");
+ return TypeOrigin(SM_STACK, index, StackMapFrame::copy(frame),
+ frame->stack_at(index));
+}
+TypeOrigin TypeOrigin::bad_index(u2 index) {
+ return TypeOrigin(BAD_INDEX, index, NULL, VerificationType::bogus_type());
+}
+TypeOrigin TypeOrigin::cp(u2 index, VerificationType vt) {
+ return TypeOrigin(CONST_POOL, index, NULL, vt);
+}
+TypeOrigin TypeOrigin::signature(VerificationType vt) {
+ return TypeOrigin(SIG, 0, NULL, vt);
+}
+TypeOrigin TypeOrigin::implicit(VerificationType t) {
+ return TypeOrigin(IMPLICIT, 0, NULL, t);
+}
+TypeOrigin TypeOrigin::frame(StackMapFrame* frame) {
+ return TypeOrigin(FRAME_ONLY, 0, StackMapFrame::copy(frame),
+ VerificationType::bogus_type());
+}
+
+void TypeOrigin::reset_frame() {
+ if (_frame != NULL) {
+ _frame->restore();
+ }
+}
+
+void TypeOrigin::details(outputStream* ss) const {
+ _type.print_on(ss);
+ switch (_origin) {
+ case CF_LOCALS:
+ ss->print(" (current frame, locals[%d])", _index);
+ break;
+ case CF_STACK:
+ ss->print(" (current frame, stack[%d])", _index);
+ break;
+ case SM_LOCALS:
+ ss->print(" (stack map, locals[%d])", _index);
+ break;
+ case SM_STACK:
+ ss->print(" (stack map, stack[%d])", _index);
+ break;
+ case CONST_POOL:
+ ss->print(" (constant pool %d)", _index);
+ break;
+ case SIG:
+ ss->print(" (from method signature)");
+ break;
+ case IMPLICIT:
+ case FRAME_ONLY:
+ case NONE:
+ default:
+ ;
+ }
+}
+
+#ifdef ASSERT
+void TypeOrigin::print_on(outputStream* str) const {
+ str->print("{%d,%d,%p:", _origin, _index, _frame);
+ if (_frame != NULL) {
+ _frame->print_on(str);
+ } else {
+ str->print("null");
+ }
+ str->print(",");
+ _type.print_on(str);
+ str->print("}");
+}
+#endif
+
+void ErrorContext::details(outputStream* ss, methodOop method) const {
+ if (is_valid()) {
+ ss->print_cr("");
+ ss->print_cr("Exception Details:");
+ location_details(ss, method);
+ reason_details(ss);
+ frame_details(ss);
+ bytecode_details(ss, method);
+ handler_details(ss, method);
+ stackmap_details(ss, method);
+ }
+}
+
+void ErrorContext::reason_details(outputStream* ss) const {
+ streamIndentor si(ss);
+ ss->indent().print_cr("Reason:");
+ streamIndentor si2(ss);
+ ss->indent().print("");
+ switch (_fault) {
+ case INVALID_BYTECODE:
+ ss->print("Error exists in the bytecode");
+ break;
+ case WRONG_TYPE:
+ if (_expected.is_valid()) {
+ ss->print("Type ");
+ _type.details(ss);
+ ss->print(" is not assignable to ");
+ _expected.details(ss);
+ } else {
+ ss->print("Invalid type: ");
+ _type.details(ss);
+ }
+ break;
+ case FLAGS_MISMATCH:
+ if (_expected.is_valid()) {
+ ss->print("Current frame's flags are not assignable "
+ "to stack map frame's.");
+ } else {
+ ss->print("Current frame's flags are invalid in this context.");
+ }
+ break;
+ case BAD_CP_INDEX:
+ ss->print("Constant pool index %d is invalid", _type.index());
+ break;
+ case BAD_LOCAL_INDEX:
+ ss->print("Local index %d is invalid", _type.index());
+ break;
+ case LOCALS_SIZE_MISMATCH:
+ ss->print("Current frame's local size doesn't match stackmap.");
+ break;
+ case STACK_SIZE_MISMATCH:
+ ss->print("Current frame's stack size doesn't match stackmap.");
+ break;
+ case STACK_OVERFLOW:
+ ss->print("Exceeded max stack size.");
+ break;
+ case STACK_UNDERFLOW:
+ ss->print("Attempt to pop empty stack.");
+ break;
+ case MISSING_STACKMAP:
+ ss->print("Expected stackmap frame at this location.");
+ break;
+ case BAD_STACKMAP:
+ ss->print("Invalid stackmap specification.");
+ break;
+ case UNKNOWN:
+ default:
+ ShouldNotReachHere();
+ ss->print_cr("Unknown");
+ }
+ ss->print_cr("");
+}
+
+void ErrorContext::location_details(outputStream* ss, methodOop method) const {
+ if (_bci != -1 && method != NULL) {
+ streamIndentor si(ss);
+ const char* bytecode_name = "<invalid>";
+ if (method->validate_bci_from_bcx(_bci) != -1) {
+ Bytecodes::Code code = Bytecodes::code_or_bp_at(method->bcp_from(_bci));
+ if (Bytecodes::is_defined(code)) {
+ bytecode_name = Bytecodes::name(code);
+ } else {
+ bytecode_name = "<illegal>";
+ }
+ }
+ instanceKlass* ik = instanceKlass::cast(method->method_holder());
+ ss->indent().print_cr("Location:");
+ streamIndentor si2(ss);
+ ss->indent().print_cr("%s.%s%s @%d: %s",
+ ik->name()->as_C_string(), method->name()->as_C_string(),
+ method->signature()->as_C_string(), _bci, bytecode_name);
+ }
+}
+
+void ErrorContext::frame_details(outputStream* ss) const {
+ streamIndentor si(ss);
+ if (_type.is_valid() && _type.frame() != NULL) {
+ ss->indent().print_cr("Current Frame:");
+ streamIndentor si2(ss);
+ _type.frame()->print_on(ss);
+ }
+ if (_expected.is_valid() && _expected.frame() != NULL) {
+ ss->indent().print_cr("Stackmap Frame:");
+ streamIndentor si2(ss);
+ _expected.frame()->print_on(ss);
+ }
+}
+
+void ErrorContext::bytecode_details(outputStream* ss, methodOop method) const {
+ if (method != NULL) {
+ streamIndentor si(ss);
+ ss->indent().print_cr("Bytecode:");
+ streamIndentor si2(ss);
+ ss->print_data(method->code_base(), method->code_size(), false);
+ }
+}
+
+void ErrorContext::handler_details(outputStream* ss, methodOop method) const {
+ if (method != NULL) {
+ streamIndentor si(ss);
+ ExceptionTable table(method);
+ if (table.length() > 0) {
+ ss->indent().print_cr("Exception Handler Table:");
+ streamIndentor si2(ss);
+ for (int i = 0; i < table.length(); ++i) {
+ ss->indent().print_cr("bci [%d, %d] => handler: %d", table.start_pc(i),
+ table.end_pc(i), table.handler_pc(i));
+ }
+ }
+ }
+}
+
+void ErrorContext::stackmap_details(outputStream* ss, methodOop method) const {
+ if (method != NULL && method->has_stackmap_table()) {
+ streamIndentor si(ss);
+ ss->indent().print_cr("Stackmap Table:");
+ typeArrayOop data = method->stackmap_data();
+ stack_map_table* sm_table =
+ stack_map_table::at((address)data->byte_at_addr(0));
+ stack_map_frame* sm_frame = sm_table->entries();
+ streamIndentor si2(ss);
+ int current_offset = -1;
+ for (u2 i = 0; i < sm_table->number_of_entries(); ++i) {
+ ss->indent();
+ sm_frame->print_on(ss, current_offset);
+ ss->print_cr("");
+ current_offset += sm_frame->offset_delta();
+ sm_frame = sm_frame->next();
+ }
+ }
+}
+
// Methods in ClassVerifier
-bool ClassVerifier::_verify_verbose = false;
-
ClassVerifier::ClassVerifier(
- instanceKlassHandle klass, char* msg, size_t msg_len, TRAPS)
- : _thread(THREAD), _exception_type(NULL), _message(msg),
- _message_buffer_len(msg_len), _klass(klass) {
+ instanceKlassHandle klass, TRAPS)
+ : _thread(THREAD), _exception_type(NULL), _message(NULL), _klass(klass) {
_this_type = VerificationType::reference_type(klass->name());
// Create list to hold symbols in reference area.
_symbols = new GrowableArray<Symbol*>(100, 0, NULL);
@@ -290,8 +535,14 @@
return VerificationType::reference_type(vmSymbols::java_lang_Object());
}
+TypeOrigin ClassVerifier::ref_ctx(const char* sig, TRAPS) {
+ VerificationType vt = VerificationType::reference_type(
+ create_temporary_symbol(sig, (int)strlen(sig), THREAD));
+ return TypeOrigin::implicit(vt);
+}
+
void ClassVerifier::verify_class(TRAPS) {
- if (_verify_verbose) {
+ if (VerboseVerification) {
tty->print_cr("Verifying class %s with new format",
_klass->external_name());
}
@@ -312,7 +563,7 @@
verify_method(methodHandle(THREAD, m), CHECK_VERIFY(this));
}
- if (_verify_verbose || TraceClassInitialization) {
+ if (VerboseVerification || TraceClassInitialization) {
if (was_recursively_verified())
tty->print_cr("Recursive verification detected for: %s",
_klass->external_name());
@@ -321,7 +572,7 @@
void ClassVerifier::verify_method(methodHandle m, TRAPS) {
_method = m; // initialize _method
- if (_verify_verbose) {
+ if (VerboseVerification) {
tty->print_cr("Verifying method %s", m->name_and_sig_as_C_string());
}
@@ -368,8 +619,8 @@
StackMapTable stackmap_table(&reader, ¤t_frame, max_locals, max_stack,
code_data, code_length, CHECK_VERIFY(this));
- if (_verify_verbose) {
- stackmap_table.print();
+ if (VerboseVerification) {
+ stackmap_table.print_on(tty);
}
RawBytecodeStream bcs(m);
@@ -388,6 +639,7 @@
// Set current frame's offset to bci
current_frame.set_offset(bci);
+ current_frame.set_mark();
// Make sure every offset in stackmap table point to the beginning to
// an instruction. Match current_frame to stackmap_table entry with
@@ -396,6 +648,7 @@
stackmap_index, bci, ¤t_frame, &stackmap_table,
no_control_flow, CHECK_VERIFY(this));
+
bool this_uninit = false; // Set to true when invokespecial <init> initialized 'this'
// Merge with the next instruction
@@ -406,8 +659,8 @@
VerificationType atype;
#ifndef PRODUCT
- if (_verify_verbose) {
- current_frame.print();
+ if (VerboseVerification) {
+ current_frame.print_on(tty);
tty->print_cr("offset = %d, opcode = %s", bci, Bytecodes::name(opcode));
}
#endif
@@ -420,7 +673,10 @@
opcode != Bytecodes::_lstore && opcode != Bytecodes::_fload &&
opcode != Bytecodes::_dload && opcode != Bytecodes::_fstore &&
opcode != Bytecodes::_dstore) {
- verify_error(bci, "Bad wide instruction");
+ /* Unreachable? RawBytecodeStream's raw_next() returns 'illegal'
+ * if we encounter a wide instruction that modifies an invalid
+ * opcode (not one of the ones listed above) */
+ verify_error(ErrorContext::bad_code(bci), "Bad wide instruction");
return;
}
}
@@ -532,7 +788,9 @@
atype = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_int_array()) {
- verify_error(bci, bad_type_msg, "iaload");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame.stack_top_ctx(), ref_ctx("[I", THREAD)),
+ bad_type_msg, "iaload");
return;
}
current_frame.push_stack(
@@ -544,7 +802,9 @@
atype = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_bool_array() && !atype.is_byte_array()) {
- verify_error(bci, bad_type_msg, "baload");
+ verify_error(
+ ErrorContext::bad_type(bci, current_frame.stack_top_ctx()),
+ bad_type_msg, "baload");
return;
}
current_frame.push_stack(
@@ -556,7 +816,9 @@
atype = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_char_array()) {
- verify_error(bci, bad_type_msg, "caload");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame.stack_top_ctx(), ref_ctx("[C", THREAD)),
+ bad_type_msg, "caload");
return;
}
current_frame.push_stack(
@@ -568,7 +830,9 @@
atype = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_short_array()) {
- verify_error(bci, bad_type_msg, "saload");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame.stack_top_ctx(), ref_ctx("[S", THREAD)),
+ bad_type_msg, "saload");
return;
}
current_frame.push_stack(
@@ -580,7 +844,9 @@
atype = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_long_array()) {
- verify_error(bci, bad_type_msg, "laload");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame.stack_top_ctx(), ref_ctx("[J", THREAD)),
+ bad_type_msg, "laload");
return;
}
current_frame.push_stack_2(
@@ -593,7 +859,9 @@
atype = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_float_array()) {
- verify_error(bci, bad_type_msg, "faload");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame.stack_top_ctx(), ref_ctx("[F", THREAD)),
+ bad_type_msg, "faload");
return;
}
current_frame.push_stack(
@@ -605,7 +873,9 @@
atype = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_double_array()) {
- verify_error(bci, bad_type_msg, "daload");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame.stack_top_ctx(), ref_ctx("[D", THREAD)),
+ bad_type_msg, "daload");
return;
}
current_frame.push_stack_2(
@@ -618,7 +888,10 @@
atype = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_reference_array()) {
- verify_error(bci, bad_type_msg, "aaload");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame.stack_top_ctx(),
+ TypeOrigin::implicit(VerificationType::reference_check())),
+ bad_type_msg, "aaload");
return;
}
if (atype.is_null()) {
@@ -689,7 +962,9 @@
atype = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_int_array()) {
- verify_error(bci, bad_type_msg, "iastore");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame.stack_top_ctx(), ref_ctx("[I", THREAD)),
+ bad_type_msg, "iastore");
return;
}
no_control_flow = false; break;
@@ -701,7 +976,9 @@
atype = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_bool_array() && !atype.is_byte_array()) {
- verify_error(bci, bad_type_msg, "bastore");
+ verify_error(
+ ErrorContext::bad_type(bci, current_frame.stack_top_ctx()),
+ bad_type_msg, "bastore");
return;
}
no_control_flow = false; break;
@@ -713,7 +990,9 @@
atype = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_char_array()) {
- verify_error(bci, bad_type_msg, "castore");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame.stack_top_ctx(), ref_ctx("[C", THREAD)),
+ bad_type_msg, "castore");
return;
}
no_control_flow = false; break;
@@ -725,7 +1004,9 @@
atype = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_short_array()) {
- verify_error(bci, bad_type_msg, "sastore");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame.stack_top_ctx(), ref_ctx("[S", THREAD)),
+ bad_type_msg, "sastore");
return;
}
no_control_flow = false; break;
@@ -738,7 +1019,9 @@
atype = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_long_array()) {
- verify_error(bci, bad_type_msg, "lastore");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame.stack_top_ctx(), ref_ctx("[J", THREAD)),
+ bad_type_msg, "lastore");
return;
}
no_control_flow = false; break;
@@ -750,7 +1033,9 @@
atype = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_float_array()) {
- verify_error(bci, bad_type_msg, "fastore");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame.stack_top_ctx(), ref_ctx("[F", THREAD)),
+ bad_type_msg, "fastore");
return;
}
no_control_flow = false; break;
@@ -763,7 +1048,9 @@
atype = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_double_array()) {
- verify_error(bci, bad_type_msg, "dastore");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame.stack_top_ctx(), ref_ctx("[D", THREAD)),
+ bad_type_msg, "dastore");
return;
}
no_control_flow = false; break;
@@ -775,7 +1062,10 @@
VerificationType::reference_check(), CHECK_VERIFY(this));
// more type-checking is done at runtime
if (!atype.is_reference_array()) {
- verify_error(bci, bad_type_msg, "aastore");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame.stack_top_ctx(),
+ TypeOrigin::implicit(VerificationType::reference_check())),
+ bad_type_msg, "aastore");
return;
}
// 4938384: relaxed constraint in JVMS 3nd edition.
@@ -793,7 +1083,11 @@
current_frame.pop_stack(
VerificationType::category2_check(), CHECK_VERIFY(this));
} else {
- verify_error(bci, bad_type_msg, "pop2");
+ /* Unreachable? Would need a category2_1st on TOS
+ * which does not appear possible. */
+ verify_error(
+ ErrorContext::bad_type(bci, current_frame.stack_top_ctx()),
+ bad_type_msg, "pop2");
return;
}
no_control_flow = false; break;
@@ -825,7 +1119,10 @@
type3 = current_frame.pop_stack(
VerificationType::category2_check(), CHECK_VERIFY(this));
} else {
- verify_error(bci, bad_type_msg, "dup_x2");
+ /* Unreachable? Would need a category2_1st at stack depth 2 with
+ * a category1 on TOS which does not appear possible. */
+ verify_error(ErrorContext::bad_type(
+ bci, current_frame.stack_top_ctx()), bad_type_msg, "dup_x2");
return;
}
current_frame.push_stack(type, CHECK_VERIFY(this));
@@ -843,7 +1140,11 @@
type2 = current_frame.pop_stack(
VerificationType::category2_check(), CHECK_VERIFY(this));
} else {
- verify_error(bci, bad_type_msg, "dup2");
+ /* Unreachable? Would need a category2_1st on TOS which does not
+ * appear possible. */
+ verify_error(
+ ErrorContext::bad_type(bci, current_frame.stack_top_ctx()),
+ bad_type_msg, "dup2");
return;
}
current_frame.push_stack(type2, CHECK_VERIFY(this));
@@ -858,11 +1159,15 @@
if (type.is_category1()) {
type2 = current_frame.pop_stack(
VerificationType::category1_check(), CHECK_VERIFY(this));
- } else if(type.is_category2_2nd()) {
- type2 = current_frame.pop_stack
- (VerificationType::category2_check(), CHECK_VERIFY(this));
+ } else if (type.is_category2_2nd()) {
+ type2 = current_frame.pop_stack(
+ VerificationType::category2_check(), CHECK_VERIFY(this));
} else {
- verify_error(bci, bad_type_msg, "dup2_x1");
+ /* Unreachable? Would need a category2_1st on TOS which does
+ * not appear possible. */
+ verify_error(
+ ErrorContext::bad_type(bci, current_frame.stack_top_ctx()),
+ bad_type_msg, "dup2_x1");
return;
}
type3 = current_frame.pop_stack(
@@ -885,7 +1190,11 @@
type2 = current_frame.pop_stack(
VerificationType::category2_check(), CHECK_VERIFY(this));
} else {
- verify_error(bci, bad_type_msg, "dup2_x2");
+ /* Unreachable? Would need a category2_1st on TOS which does
+ * not appear possible. */
+ verify_error(
+ ErrorContext::bad_type(bci, current_frame.stack_top_ctx()),
+ bad_type_msg, "dup2_x2");
return;
}
type3 = current_frame.pop_stack(CHECK_VERIFY(this));
@@ -896,7 +1205,12 @@
type4 = current_frame.pop_stack(
VerificationType::category2_check(), CHECK_VERIFY(this));
} else {
- verify_error(bci, bad_type_msg, "dup2_x2");
+ /* Unreachable? Would need a category2_1st on TOS after popping
+ * a long/double or two category 1's, which does not
+ * appear possible. */
+ verify_error(
+ ErrorContext::bad_type(bci, current_frame.stack_top_ctx()),
+ bad_type_msg, "dup2_x2");
return;
}
current_frame.push_stack(type2, CHECK_VERIFY(this));
@@ -1176,43 +1490,50 @@
case Bytecodes::_ireturn :
type = current_frame.pop_stack(
VerificationType::integer_type(), CHECK_VERIFY(this));
- verify_return_value(return_type, type, bci, CHECK_VERIFY(this));
+ verify_return_value(return_type, type, bci,
+ ¤t_frame, CHECK_VERIFY(this));
no_control_flow = true; break;
case Bytecodes::_lreturn :
type2 = current_frame.pop_stack(
VerificationType::long2_type(), CHECK_VERIFY(this));
type = current_frame.pop_stack(
VerificationType::long_type(), CHECK_VERIFY(this));
- verify_return_value(return_type, type, bci, CHECK_VERIFY(this));
+ verify_return_value(return_type, type, bci,
+ ¤t_frame, CHECK_VERIFY(this));
no_control_flow = true; break;
case Bytecodes::_freturn :
type = current_frame.pop_stack(
VerificationType::float_type(), CHECK_VERIFY(this));
- verify_return_value(return_type, type, bci, CHECK_VERIFY(this));
+ verify_return_value(return_type, type, bci,
+ ¤t_frame, CHECK_VERIFY(this));
no_control_flow = true; break;
case Bytecodes::_dreturn :
type2 = current_frame.pop_stack(
VerificationType::double2_type(), CHECK_VERIFY(this));
type = current_frame.pop_stack(
VerificationType::double_type(), CHECK_VERIFY(this));
- verify_return_value(return_type, type, bci, CHECK_VERIFY(this));
+ verify_return_value(return_type, type, bci,
+ ¤t_frame, CHECK_VERIFY(this));
no_control_flow = true; break;
case Bytecodes::_areturn :
type = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
- verify_return_value(return_type, type, bci, CHECK_VERIFY(this));
+ verify_return_value(return_type, type, bci,
+ ¤t_frame, CHECK_VERIFY(this));
no_control_flow = true; break;
case Bytecodes::_return :
if (return_type != VerificationType::bogus_type()) {
- verify_error(bci, "Method expects no return value");
+ verify_error(ErrorContext::bad_code(bci),
+ "Method expects a return value");
return;
}
// Make sure "this" has been initialized if current method is an
// <init>
if (_method->name() == vmSymbols::object_initializer_name() &&
current_frame.flag_this_uninit()) {
- verify_error(bci,
- "Constructor must call super() or this() before return");
+ verify_error(ErrorContext::bad_code(bci),
+ "Constructor must call super() or this() "
+ "before return");
return;
}
no_control_flow = true; break;
@@ -1239,11 +1560,13 @@
case Bytecodes::_new :
{
index = bcs.get_index_u2();
- verify_cp_class_type(index, cp, CHECK_VERIFY(this));
+ verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));
VerificationType new_class_type =
cp_index_to_type(index, cp, CHECK_VERIFY(this));
if (!new_class_type.is_object()) {
- verify_error(bci, "Illegal new instruction");
+ verify_error(ErrorContext::bad_type(bci,
+ TypeOrigin::cp(index, new_class_type)),
+ "Illegal new instruction");
return;
}
type = VerificationType::uninitialized_type(bci);
@@ -1258,13 +1581,15 @@
no_control_flow = false; break;
case Bytecodes::_anewarray :
verify_anewarray(
- bcs.get_index_u2(), cp, ¤t_frame, CHECK_VERIFY(this));
+ bci, bcs.get_index_u2(), cp, ¤t_frame, CHECK_VERIFY(this));
no_control_flow = false; break;
case Bytecodes::_arraylength :
type = current_frame.pop_stack(
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!(type.is_null() || type.is_array())) {
- verify_error(bci, bad_type_msg, "arraylength");
+ verify_error(ErrorContext::bad_type(
+ bci, current_frame.stack_top_ctx()),
+ bad_type_msg, "arraylength");
}
current_frame.push_stack(
VerificationType::integer_type(), CHECK_VERIFY(this));
@@ -1272,7 +1597,7 @@
case Bytecodes::_checkcast :
{
index = bcs.get_index_u2();
- verify_cp_class_type(index, cp, CHECK_VERIFY(this));
+ verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));
current_frame.pop_stack(object_type(), CHECK_VERIFY(this));
VerificationType klass_type = cp_index_to_type(
index, cp, CHECK_VERIFY(this));
@@ -1281,7 +1606,7 @@
}
case Bytecodes::_instanceof : {
index = bcs.get_index_u2();
- verify_cp_class_type(index, cp, CHECK_VERIFY(this));
+ verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));
current_frame.pop_stack(object_type(), CHECK_VERIFY(this));
current_frame.push_stack(
VerificationType::integer_type(), CHECK_VERIFY(this));
@@ -1296,17 +1621,18 @@
{
index = bcs.get_index_u2();
u2 dim = *(bcs.bcp()+3);
- verify_cp_class_type(index, cp, CHECK_VERIFY(this));
+ verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));
VerificationType new_array_type =
cp_index_to_type(index, cp, CHECK_VERIFY(this));
if (!new_array_type.is_array()) {
- verify_error(bci,
- "Illegal constant pool index in multianewarray instruction");
+ verify_error(ErrorContext::bad_type(bci,
+ TypeOrigin::cp(index, new_array_type)),
+ "Illegal constant pool index in multianewarray instruction");
return;
}
if (dim < 1 || new_array_type.dimensions() < dim) {
- verify_error(bci,
- "Illegal dimension in multianewarray instruction");
+ verify_error(ErrorContext::bad_code(bci),
+ "Illegal dimension in multianewarray instruction: %d", dim);
return;
}
for (int i = 0; i < dim; i++) {
@@ -1324,7 +1650,8 @@
default:
// We only need to check the valid bytecodes in class file.
// And jsr and ret are not in the new class file format in JDK1.5.
- verify_error(bci, "Bad instruction");
+ verify_error(ErrorContext::bad_code(bci),
+ "Bad instruction: %02x", opcode);
no_control_flow = false;
return;
} // end switch
@@ -1340,7 +1667,8 @@
// Make sure that control flow does not fall through end of the method
if (!no_control_flow) {
- verify_error(code_length, "Control flow falls through code end");
+ verify_error(ErrorContext::bad_code(code_length),
+ "Control flow falls through code end");
return;
}
}
@@ -1359,7 +1687,7 @@
code_data[bci] = BYTECODE_OFFSET;
}
} else {
- verify_error(bcs.bci(), "Bad instruction");
+ verify_error(ErrorContext::bad_code(bcs.bci()), "Bad instruction");
return NULL;
}
}
@@ -1402,9 +1730,11 @@
catch_type, this, CHECK_VERIFY(this));
if (!is_subclass) {
// 4286534: should throw VerifyError according to recent spec change
- verify_error(
- "Catch type is not a subclass of Throwable in handler %d",
- handler_pc);
+ verify_error(ErrorContext::bad_type(handler_pc,
+ TypeOrigin::cp(catch_type_index, catch_type),
+ TypeOrigin::implicit(throwable)),
+ "Catch type is not a subclass "
+ "of Throwable in exception handler %d", handler_pc);
return;
}
}
@@ -1444,19 +1774,21 @@
if (stackmap_index < stackmap_table->get_frame_count()) {
u2 this_offset = stackmap_table->get_offset(stackmap_index);
if (no_control_flow && this_offset > bci) {
- verify_error(bci, "Expecting a stack map frame");
+ verify_error(ErrorContext::missing_stackmap(bci),
+ "Expecting a stack map frame");
return 0;
}
if (this_offset == bci) {
+ ErrorContext ctx;
// See if current stack map can be assigned to the frame in table.
// current_frame is the stackmap frame got from the last instruction.
// If matched, current_frame will be updated by this method.
- bool match = stackmap_table->match_stackmap(
+ bool matches = stackmap_table->match_stackmap(
current_frame, this_offset, stackmap_index,
- !no_control_flow, true, CHECK_VERIFY_(this, 0));
- if (!match) {
+ !no_control_flow, true, &ctx, CHECK_VERIFY_(this, 0));
+ if (!matches) {
// report type error
- verify_error(bci, "Instruction type does not match stack map");
+ verify_error(ctx, "Instruction type does not match stack map");
return 0;
}
stackmap_index++;
@@ -1466,7 +1798,7 @@
return 0;
}
} else if (no_control_flow) {
- verify_error(bci, "Expecting a stack map frame");
+ verify_error(ErrorContext::bad_code(bci), "Expecting a stack map frame");
return 0;
}
return stackmap_index;
@@ -1498,29 +1830,31 @@
VerificationType::reference_type(vmSymbols::java_lang_Throwable());
new_frame->push_stack(throwable, CHECK_VERIFY(this));
}
- bool match = stackmap_table->match_stackmap(
- new_frame, handler_pc, true, false, CHECK_VERIFY(this));
- if (!match) {
- verify_error(bci,
- "Stack map does not match the one at exception handler %d",
- handler_pc);
+ ErrorContext ctx;
+ bool matches = stackmap_table->match_stackmap(
+ new_frame, handler_pc, true, false, &ctx, CHECK_VERIFY(this));
+ if (!matches) {
+ verify_error(ctx, "Stack map does not match the one at "
+ "exception handler %d", handler_pc);
return;
}
}
}
}
-void ClassVerifier::verify_cp_index(constantPoolHandle cp, int index, TRAPS) {
+void ClassVerifier::verify_cp_index(
+ u2 bci, constantPoolHandle cp, int index, TRAPS) {
int nconstants = cp->length();
if ((index <= 0) || (index >= nconstants)) {
- verify_error("Illegal constant pool index %d in class %s",
- index, instanceKlass::cast(cp->pool_holder())->external_name());
+ verify_error(ErrorContext::bad_cp_index(bci, index),
+ "Illegal constant pool index %d in class %s",
+ index, instanceKlass::cast(cp->pool_holder())->external_name());
return;
}
}
void ClassVerifier::verify_cp_type(
- int index, constantPoolHandle cp, unsigned int types, TRAPS) {
+ u2 bci, int index, constantPoolHandle cp, unsigned int types, TRAPS) {
// In some situations, bytecode rewriting may occur while we're verifying.
// In this case, a constant pool cache exists and some indices refer to that
@@ -1528,10 +1862,10 @@
// We must check was_recursively_verified() before we get here.
guarantee(cp->cache() == NULL, "not rewritten yet");
- verify_cp_index(cp, index, CHECK_VERIFY(this));
+ verify_cp_index(bci, cp, index, CHECK_VERIFY(this));
unsigned int tag = cp->tag_at(index).value();
if ((types & (1 << tag)) == 0) {
- verify_error(
+ verify_error(ErrorContext::bad_cp_index(bci, index),
"Illegal type at constant pool entry %d in class %s",
index, instanceKlass::cast(cp->pool_holder())->external_name());
return;
@@ -1539,51 +1873,46 @@
}
void ClassVerifier::verify_cp_class_type(
- int index, constantPoolHandle cp, TRAPS) {
- verify_cp_index(cp, index, CHECK_VERIFY(this));
+ u2 bci, int index, constantPoolHandle cp, TRAPS) {
+ verify_cp_index(bci, cp, index, CHECK_VERIFY(this));
constantTag tag = cp->tag_at(index);
if (!tag.is_klass() && !tag.is_unresolved_klass()) {
- verify_error("Illegal type at constant pool entry %d in class %s",
- index, instanceKlass::cast(cp->pool_holder())->external_name());
+ verify_error(ErrorContext::bad_cp_index(bci, index),
+ "Illegal type at constant pool entry %d in class %s",
+ index, instanceKlass::cast(cp->pool_holder())->external_name());
return;
}
}
-void ClassVerifier::format_error_message(
- const char* fmt, int offset, va_list va) {
- ResourceMark rm(_thread);
- stringStream message(_message, _message_buffer_len);
- message.vprint(fmt, va);
- if (!_method.is_null()) {
- message.print(" in method %s", _method->name_and_sig_as_C_string());
- }
- if (offset != -1) {
- message.print(" at offset %d", offset);
- }
-}
+void ClassVerifier::verify_error(ErrorContext ctx, const char* msg, ...) {
+ stringStream ss;
-void ClassVerifier::verify_error(u2 offset, const char* fmt, ...) {
+ ctx.reset_frames();
_exception_type = vmSymbols::java_lang_VerifyError();
+ _error_context = ctx;
va_list va;
- va_start(va, fmt);
- format_error_message(fmt, offset, va);
+ va_start(va, msg);
+ ss.vprint(msg, va);
va_end(va);
-}
-
-void ClassVerifier::verify_error(const char* fmt, ...) {
- _exception_type = vmSymbols::java_lang_VerifyError();
- va_list va;
- va_start(va, fmt);
- format_error_message(fmt, -1, va);
- va_end(va);
+ _message = ss.as_string();
+#ifdef ASSERT
+ ResourceMark rm;
+ const char* exception_name = _exception_type->as_C_string();
+ Exceptions::debug_check_abort(exception_name, NULL);
+#endif // ndef ASSERT
}
void ClassVerifier::class_format_error(const char* msg, ...) {
+ stringStream ss;
_exception_type = vmSymbols::java_lang_ClassFormatError();
va_list va;
va_start(va, msg);
- format_error_message(msg, -1, va);
+ ss.vprint(msg, va);
va_end(va);
+ if (!_method.is_null()) {
+ ss.print(" in method %s", _method->name_and_sig_as_C_string());
+ }
+ _message = ss.as_string();
}
klassOop ClassVerifier::load_class(Symbol* name, TRAPS) {
@@ -1619,7 +1948,7 @@
}
} else {
klassOop member_klass = target_instance->find_field(field_name, field_sig, &fd);
- if(member_klass != NULL && fd.is_protected()) {
+ if (member_klass != NULL && fd.is_protected()) {
if (!this_class->is_same_class_package(member_klass)) {
return true;
}
@@ -1629,9 +1958,9 @@
}
void ClassVerifier::verify_ldc(
- int opcode, u2 index, StackMapFrame *current_frame,
- constantPoolHandle cp, u2 bci, TRAPS) {
- verify_cp_index(cp, index, CHECK_VERIFY(this));
+ int opcode, u2 index, StackMapFrame* current_frame,
+ constantPoolHandle cp, u2 bci, TRAPS) {
+ verify_cp_index(bci, cp, index, CHECK_VERIFY(this));
constantTag tag = cp->tag_at(index);
unsigned int types;
if (opcode == Bytecodes::_ldc || opcode == Bytecodes::_ldc_w) {
@@ -1641,12 +1970,12 @@
| (1 << JVM_CONSTANT_MethodHandle) | (1 << JVM_CONSTANT_MethodType);
// Note: The class file parser already verified the legality of
// MethodHandle and MethodType constants.
- verify_cp_type(index, cp, types, CHECK_VERIFY(this));
+ verify_cp_type(bci, index, cp, types, CHECK_VERIFY(this));
}
} else {
assert(opcode == Bytecodes::_ldc2_w, "must be ldc2_w");
types = (1 << JVM_CONSTANT_Double) | (1 << JVM_CONSTANT_Long);
- verify_cp_type(index, cp, types, CHECK_VERIFY(this));
+ verify_cp_type(bci, index, cp, types, CHECK_VERIFY(this));
}
if (tag.is_string() && cp->is_pseudo_string_at(index)) {
current_frame->push_stack(object_type(), CHECK_VERIFY(this));
@@ -1681,7 +2010,9 @@
VerificationType::reference_type(
vmSymbols::java_lang_invoke_MethodType()), CHECK_VERIFY(this));
} else {
- verify_error(bci, "Invalid index in ldc");
+ /* Unreachable? verify_cp_type has already validated the cp type. */
+ verify_error(
+ ErrorContext::bad_cp_index(bci, index), "Invalid index in ldc");
return;
}
}
@@ -1697,7 +2028,8 @@
u2 padding_offset = 1;
while ((bcp + padding_offset) < aligned_bcp) {
if(*(bcp + padding_offset) != 0) {
- verify_error(bci, "Nonzero padding byte in lookswitch or tableswitch");
+ verify_error(ErrorContext::bad_code(bci),
+ "Nonzero padding byte in lookswitch or tableswitch");
return;
}
padding_offset++;
@@ -1710,20 +2042,21 @@
jint low = (jint)Bytes::get_Java_u4(aligned_bcp + jintSize);
jint high = (jint)Bytes::get_Java_u4(aligned_bcp + 2*jintSize);
if (low > high) {
- verify_error(bci,
- "low must be less than or equal to high in tableswitch");
+ verify_error(ErrorContext::bad_code(bci),
+ "low must be less than or equal to high in tableswitch");
return;
}
keys = high - low + 1;
if (keys < 0) {
- verify_error(bci, "too many keys in tableswitch");
+ verify_error(ErrorContext::bad_code(bci), "too many keys in tableswitch");
return;
}
delta = 1;
} else {
keys = (int)Bytes::get_Java_u4(aligned_bcp + jintSize);
if (keys < 0) {
- verify_error(bci, "number of keys in lookupswitch less than 0");
+ verify_error(ErrorContext::bad_code(bci),
+ "number of keys in lookupswitch less than 0");
return;
}
delta = 2;
@@ -1732,7 +2065,8 @@
jint this_key = Bytes::get_Java_u4(aligned_bcp + (2+2*i)*jintSize);
jint next_key = Bytes::get_Java_u4(aligned_bcp + (2+2*i+2)*jintSize);
if (this_key >= next_key) {
- verify_error(bci, "Bad lookupswitch instruction");
+ verify_error(ErrorContext::bad_code(bci),
+ "Bad lookupswitch instruction");
return;
}
}
@@ -1767,7 +2101,8 @@
constantPoolHandle cp,
TRAPS) {
u2 index = bcs->get_index_u2();
- verify_cp_type(index, cp, 1 << JVM_CONSTANT_Fieldref, CHECK_VERIFY(this));
+ verify_cp_type(bcs->bci(), index, cp,
+ 1 << JVM_CONSTANT_Fieldref, CHECK_VERIFY(this));
// Get field name and signature
Symbol* field_name = cp->name_ref_at(index);
@@ -1784,9 +2119,11 @@
VerificationType ref_class_type = cp_ref_index_to_type(
index, cp, CHECK_VERIFY(this));
if (!ref_class_type.is_object()) {
- verify_error(
- "Expecting reference to class in class %s at constant pool index %d",
- _klass->external_name(), index);
+ /* Unreachable? Class file parser verifies Fieldref contents */
+ verify_error(ErrorContext::bad_type(bcs->bci(),
+ TypeOrigin::cp(index, ref_class_type)),
+ "Expecting reference to class in class %s at constant pool index %d",
+ _klass->external_name(), index);
return;
}
VerificationType target_class_type = ref_class_type;
@@ -1844,7 +2181,10 @@
is_assignable = target_class_type.is_assignable_from(
stack_object_type, this, CHECK_VERIFY(this));
if (!is_assignable) {
- verify_error(bci, "Bad type on operand stack in putfield");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame->stack_top_ctx(),
+ TypeOrigin::cp(index, target_class_type)),
+ "Bad type on operand stack in putfield");
return;
}
}
@@ -1868,7 +2208,10 @@
is_assignable = current_type().is_assignable_from(
stack_object_type, this, CHECK_VERIFY(this));
if (!is_assignable) {
- verify_error(bci, "Bad access to protected data in getfield");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame->stack_top_ctx(),
+ TypeOrigin::implicit(current_type())),
+ "Bad access to protected data in getfield");
return;
}
}
@@ -1879,7 +2222,7 @@
}
void ClassVerifier::verify_invoke_init(
- RawBytecodeStream* bcs, VerificationType ref_class_type,
+ RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type,
StackMapFrame* current_frame, u4 code_length, bool *this_uninit,
constantPoolHandle cp, TRAPS) {
u2 bci = bcs->bci();
@@ -1890,7 +2233,10 @@
klassOop superk = current_class()->super();
if (ref_class_type.name() != current_class()->name() &&
ref_class_type.name() != superk->klass_part()->name()) {
- verify_error(bci, "Bad <init> method call");
+ verify_error(ErrorContext::bad_type(bci,
+ TypeOrigin::implicit(ref_class_type),
+ TypeOrigin::implicit(current_type())),
+ "Bad <init> method call");
return;
}
current_frame->initialize_object(type, current_type());
@@ -1899,17 +2245,23 @@
u2 new_offset = type.bci();
address new_bcp = bcs->bcp() - bci + new_offset;
if (new_offset > (code_length - 3) || (*new_bcp) != Bytecodes::_new) {
- verify_error(new_offset, "Expecting new instruction");
+ /* Unreachable? Stack map parsing ensures valid type and new
+ * instructions have a valid BCI. */
+ verify_error(ErrorContext::bad_code(new_offset),
+ "Expecting new instruction");
return;
}
u2 new_class_index = Bytes::get_Java_u2(new_bcp + 1);
- verify_cp_class_type(new_class_index, cp, CHECK_VERIFY(this));
+ verify_cp_class_type(bci, new_class_index, cp, CHECK_VERIFY(this));
// The method must be an <init> method of the indicated class
VerificationType new_class_type = cp_index_to_type(
new_class_index, cp, CHECK_VERIFY(this));
if (!new_class_type.equals(ref_class_type)) {
- verify_error(bci, "Call to wrong <init> method");
+ verify_error(ErrorContext::bad_type(bci,
+ TypeOrigin::cp(new_class_index, new_class_type),
+ TypeOrigin::cp(ref_class_index, ref_class_type)),
+ "Call to wrong <init> method");
return;
}
// According to the VM spec, if the referent class is a superclass of the
@@ -1928,14 +2280,18 @@
bool assignable = current_type().is_assignable_from(
objectref_type, this, CHECK_VERIFY(this));
if (!assignable) {
- verify_error(bci, "Bad access to protected <init> method");
+ verify_error(ErrorContext::bad_type(bci,
+ TypeOrigin::cp(new_class_index, objectref_type),
+ TypeOrigin::implicit(current_type())),
+ "Bad access to protected <init> method");
return;
}
}
}
current_frame->initialize_object(type, new_class_type);
} else {
- verify_error(bci, "Bad operand type when invoking <init>");
+ verify_error(ErrorContext::bad_type(bci, current_frame->stack_top_ctx()),
+ "Bad operand type when invoking <init>");
return;
}
}
@@ -1952,7 +2308,7 @@
: opcode == Bytecodes::_invokedynamic
? 1 << JVM_CONSTANT_InvokeDynamic
: 1 << JVM_CONSTANT_Methodref);
- verify_cp_type(index, cp, types, CHECK_VERIFY(this));
+ verify_cp_type(bcs->bci(), index, cp, types, CHECK_VERIFY(this));
// Get method name and signature
Symbol* method_name = cp->name_ref_at(index);
@@ -2029,11 +2385,13 @@
// the difference between the size of the operand stack before and after the instruction
// executes.
if (*(bcp+3) != (nargs+1)) {
- verify_error(bci, "Inconsistent args count operand in invokeinterface");
+ verify_error(ErrorContext::bad_code(bci),
+ "Inconsistent args count operand in invokeinterface");
return;
}
if (*(bcp+4) != 0) {
- verify_error(bci, "Fourth operand byte of invokeinterface must be zero");
+ verify_error(ErrorContext::bad_code(bci),
+ "Fourth operand byte of invokeinterface must be zero");
return;
}
}
@@ -2041,7 +2399,8 @@
if (opcode == Bytecodes::_invokedynamic) {
address bcp = bcs->bcp();
if (*(bcp+3) != 0 || *(bcp+4) != 0) {
- verify_error(bci, "Third and fourth operand bytes of invokedynamic must be zero");
+ verify_error(ErrorContext::bad_code(bci),
+ "Third and fourth operand bytes of invokedynamic must be zero");
return;
}
}
@@ -2050,7 +2409,8 @@
// Make sure <init> can only be invoked by invokespecial
if (opcode != Bytecodes::_invokespecial ||
method_name != vmSymbols::object_initializer_name()) {
- verify_error(bci, "Illegal call to internal method");
+ verify_error(ErrorContext::bad_code(bci),
+ "Illegal call to internal method");
return;
}
} else if (opcode == Bytecodes::_invokespecial
@@ -2060,7 +2420,8 @@
bool subtype = ref_class_type.is_assignable_from(
current_type(), this, CHECK_VERIFY(this));
if (!subtype) {
- verify_error(bci, "Bad invokespecial instruction: "
+ verify_error(ErrorContext::bad_code(bci),
+ "Bad invokespecial instruction: "
"current class isn't assignable to reference class.");
return;
}
@@ -2073,7 +2434,7 @@
if (opcode != Bytecodes::_invokestatic &&
opcode != Bytecodes::_invokedynamic) {
if (method_name == vmSymbols::object_initializer_name()) { // <init> method
- verify_invoke_init(bcs, ref_class_type, current_frame,
+ verify_invoke_init(bcs, index, ref_class_type, current_frame,
code_length, this_uninit, cp, CHECK_VERIFY(this));
} else { // other methods
// Ensures that target class is assignable to method class.
@@ -2103,8 +2464,10 @@
// Special case: arrays pretend to implement public Object
// clone().
} else {
- verify_error(bci,
- "Bad access to protected data in invokevirtual");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame->stack_top_ctx(),
+ TypeOrigin::implicit(current_type())),
+ "Bad access to protected data in invokevirtual");
return;
}
}
@@ -2121,7 +2484,10 @@
if (sig_stream.type() != T_VOID) {
if (method_name == vmSymbols::object_initializer_name()) {
// <init> method must have a void return type
- verify_error(bci, "Return type must be void in <init> method");
+ /* Unreachable? Class file parser verifies that methods with '<' have
+ * void return */
+ verify_error(ErrorContext::bad_code(bci),
+ "Return type must be void in <init> method");
return;
}
VerificationType return_type[2];
@@ -2139,7 +2505,7 @@
NULL, NULL, NULL, NULL, "[Z", "[C", "[F", "[D", "[B", "[S", "[I", "[J",
};
if (index < T_BOOLEAN || index > T_LONG) {
- verify_error(bci, "Illegal newarray instruction");
+ verify_error(ErrorContext::bad_code(bci), "Illegal newarray instruction");
return VerificationType::bogus_type();
}
@@ -2150,8 +2516,9 @@
}
void ClassVerifier::verify_anewarray(
- u2 index, constantPoolHandle cp, StackMapFrame* current_frame, TRAPS) {
- verify_cp_class_type(index, cp, CHECK_VERIFY(this));
+ u2 bci, u2 index, constantPoolHandle cp,
+ StackMapFrame* current_frame, TRAPS) {
+ verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));
current_frame->pop_stack(
VerificationType::integer_type(), CHECK_VERIFY(this));
@@ -2264,14 +2631,19 @@
}
void ClassVerifier::verify_return_value(
- VerificationType return_type, VerificationType type, u2 bci, TRAPS) {
+ VerificationType return_type, VerificationType type, u2 bci,
+ StackMapFrame* current_frame, TRAPS) {
if (return_type == VerificationType::bogus_type()) {
- verify_error(bci, "Method expects a return value");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame->stack_top_ctx(), TypeOrigin::signature(return_type)),
+ "Method expects a return value");
return;
}
bool match = return_type.is_assignable_from(type, this, CHECK_VERIFY(this));
if (!match) {
- verify_error(bci, "Bad return type");
+ verify_error(ErrorContext::bad_type(bci,
+ current_frame->stack_top_ctx(), TypeOrigin::signature(return_type)),
+ "Bad return type");
return;
}
}
--- a/hotspot/src/share/vm/classfile/verifier.hpp Mon Aug 06 09:34:40 2012 -0700
+++ b/hotspot/src/share/vm/classfile/verifier.hpp Mon Aug 06 15:54:45 2012 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2012, 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
@@ -88,18 +88,178 @@
#define CHECK_VERIFY_(verifier, result) \
CHECK_(result)); if ((verifier)->has_error()) return (result); (0
+class TypeOrigin VALUE_OBJ_CLASS_SPEC {
+ private:
+ typedef enum {
+ CF_LOCALS, // Comes from the current frame locals
+ CF_STACK, // Comes from the current frame expression stack
+ SM_LOCALS, // Comes from stackmap locals
+ SM_STACK, // Comes from stackmap expression stack
+ CONST_POOL, // Comes from the constant pool
+ SIG, // Comes from method signature
+ IMPLICIT, // Comes implicitly from code or context
+ BAD_INDEX, // No type, but the index is bad
+ FRAME_ONLY, // No type, context just contains the frame
+ NONE
+ } Origin;
+
+ Origin _origin;
+ u2 _index; // local, stack, or constant pool index
+ StackMapFrame* _frame; // source frame if CF or SM
+ VerificationType _type; // The actual type
+
+ TypeOrigin(
+ Origin origin, u2 index, StackMapFrame* frame, VerificationType type)
+ : _origin(origin), _index(index), _frame(frame), _type(type) {}
+
+ public:
+ TypeOrigin() : _origin(NONE), _index(0), _frame(NULL) {}
+
+ static TypeOrigin null();
+ static TypeOrigin local(u2 index, StackMapFrame* frame);
+ static TypeOrigin stack(u2 index, StackMapFrame* frame);
+ static TypeOrigin sm_local(u2 index, StackMapFrame* frame);
+ static TypeOrigin sm_stack(u2 index, StackMapFrame* frame);
+ static TypeOrigin cp(u2 index, VerificationType vt);
+ static TypeOrigin signature(VerificationType vt);
+ static TypeOrigin bad_index(u2 index);
+ static TypeOrigin implicit(VerificationType t);
+ static TypeOrigin frame(StackMapFrame* frame);
+
+ void reset_frame();
+ void details(outputStream* ss) const;
+ void print_frame(outputStream* ss) const;
+ const StackMapFrame* frame() const { return _frame; }
+ bool is_valid() const { return _origin != NONE; }
+ u2 index() const { return _index; }
+
+#ifdef ASSERT
+ void print_on(outputStream* str) const;
+#endif
+};
+
+class ErrorContext VALUE_OBJ_CLASS_SPEC {
+ private:
+ typedef enum {
+ INVALID_BYTECODE, // There was a problem with the bytecode
+ WRONG_TYPE, // Type value was not as expected
+ FLAGS_MISMATCH, // Frame flags are not assignable
+ BAD_CP_INDEX, // Invalid constant pool index
+ BAD_LOCAL_INDEX, // Invalid local index
+ LOCALS_SIZE_MISMATCH, // Frames have differing local counts
+ STACK_SIZE_MISMATCH, // Frames have different stack sizes
+ STACK_OVERFLOW, // Attempt to push onto a full expression stack
+ STACK_UNDERFLOW, // Attempt to pop and empty expression stack
+ MISSING_STACKMAP, // No stackmap for this location and there should be
+ BAD_STACKMAP, // Format error in stackmap
+ NO_FAULT, // No error
+ UNKNOWN
+ } FaultType;
+
+ int _bci;
+ FaultType _fault;
+ TypeOrigin _type;
+ TypeOrigin _expected;
+
+ ErrorContext(int bci, FaultType fault) :
+ _bci(bci), _fault(fault) {}
+ ErrorContext(int bci, FaultType fault, TypeOrigin type) :
+ _bci(bci), _fault(fault), _type(type) {}
+ ErrorContext(int bci, FaultType fault, TypeOrigin type, TypeOrigin exp) :
+ _bci(bci), _fault(fault), _type(type), _expected(exp) {}
+
+ public:
+ ErrorContext() : _bci(-1), _fault(NO_FAULT) {}
+
+ static ErrorContext bad_code(u2 bci) {
+ return ErrorContext(bci, INVALID_BYTECODE);
+ }
+ static ErrorContext bad_type(u2 bci, TypeOrigin type) {
+ return ErrorContext(bci, WRONG_TYPE, type);
+ }
+ static ErrorContext bad_type(u2 bci, TypeOrigin type, TypeOrigin exp) {
+ return ErrorContext(bci, WRONG_TYPE, type, exp);
+ }
+ static ErrorContext bad_flags(u2 bci, StackMapFrame* frame) {
+ return ErrorContext(bci, FLAGS_MISMATCH, TypeOrigin::frame(frame));
+ }
+ static ErrorContext bad_flags(u2 bci, StackMapFrame* cur, StackMapFrame* sm) {
+ return ErrorContext(bci, FLAGS_MISMATCH,
+ TypeOrigin::frame(cur), TypeOrigin::frame(sm));
+ }
+ static ErrorContext bad_cp_index(u2 bci, u2 index) {
+ return ErrorContext(bci, BAD_CP_INDEX, TypeOrigin::bad_index(index));
+ }
+ static ErrorContext bad_local_index(u2 bci, u2 index) {
+ return ErrorContext(bci, BAD_LOCAL_INDEX, TypeOrigin::bad_index(index));
+ }
+ static ErrorContext locals_size_mismatch(
+ u2 bci, StackMapFrame* frame0, StackMapFrame* frame1) {
+ return ErrorContext(bci, LOCALS_SIZE_MISMATCH,
+ TypeOrigin::frame(frame0), TypeOrigin::frame(frame1));
+ }
+ static ErrorContext stack_size_mismatch(
+ u2 bci, StackMapFrame* frame0, StackMapFrame* frame1) {
+ return ErrorContext(bci, STACK_SIZE_MISMATCH,
+ TypeOrigin::frame(frame0), TypeOrigin::frame(frame1));
+ }
+ static ErrorContext stack_overflow(u2 bci, StackMapFrame* frame) {
+ return ErrorContext(bci, STACK_OVERFLOW, TypeOrigin::frame(frame));
+ }
+ static ErrorContext stack_underflow(u2 bci, StackMapFrame* frame) {
+ return ErrorContext(bci, STACK_UNDERFLOW, TypeOrigin::frame(frame));
+ }
+ static ErrorContext missing_stackmap(u2 bci) {
+ return ErrorContext(bci, MISSING_STACKMAP);
+ }
+ static ErrorContext bad_stackmap(int index, StackMapFrame* frame) {
+ return ErrorContext(0, BAD_STACKMAP, TypeOrigin::frame(frame));
+ }
+
+ bool is_valid() const { return _fault != NO_FAULT; }
+ int bci() const { return _bci; }
+
+ void reset_frames() {
+ _type.reset_frame();
+ _expected.reset_frame();
+ }
+
+ void details(outputStream* ss, methodOop method) const;
+
+#ifdef ASSERT
+ void print_on(outputStream* str) const {
+ str->print("error_context(%d, %d,", _bci, _fault);
+ _type.print_on(str);
+ str->print(",");
+ _expected.print_on(str);
+ str->print(")");
+ }
+#endif
+
+ private:
+ void location_details(outputStream* ss, methodOop method) const;
+ void reason_details(outputStream* ss) const;
+ void frame_details(outputStream* ss) const;
+ void bytecode_details(outputStream* ss, methodOop method) const;
+ void handler_details(outputStream* ss, methodOop method) const;
+ void stackmap_details(outputStream* ss, methodOop method) const;
+};
+
// A new instance of this class is created for each class being verified
class ClassVerifier : public StackObj {
private:
Thread* _thread;
+ GrowableArray<Symbol*>* _symbols; // keep a list of symbols created
+
Symbol* _exception_type;
char* _message;
- size_t _message_buffer_len;
- GrowableArray<Symbol*>* _symbols; // keep a list of symbols created
+
+ ErrorContext _error_context; // contains information about an error
void verify_method(methodHandle method, TRAPS);
char* generate_code_data(methodHandle m, u4 code_length, TRAPS);
- void verify_exception_handler_table(u4 code_length, char* code_data, int& min, int& max, TRAPS);
+ void verify_exception_handler_table(u4 code_length, char* code_data,
+ int& min, int& max, TRAPS);
void verify_local_variable_table(u4 code_length, char* code_data, TRAPS);
VerificationType cp_ref_index_to_type(
@@ -111,10 +271,10 @@
instanceKlassHandle this_class, klassOop target_class,
Symbol* field_name, Symbol* field_sig, bool is_method);
- void verify_cp_index(constantPoolHandle cp, int index, TRAPS);
- void verify_cp_type(
- int index, constantPoolHandle cp, unsigned int types, TRAPS);
- void verify_cp_class_type(int index, constantPoolHandle cp, TRAPS);
+ void verify_cp_index(u2 bci, constantPoolHandle cp, int index, TRAPS);
+ void verify_cp_type(u2 bci, int index, constantPoolHandle cp,
+ unsigned int types, TRAPS);
+ void verify_cp_class_type(u2 bci, int index, constantPoolHandle cp, TRAPS);
u2 verify_stackmap_table(
u2 stackmap_index, u2 bci, StackMapFrame* current_frame,
@@ -137,7 +297,7 @@
constantPoolHandle cp, TRAPS);
void verify_invoke_init(
- RawBytecodeStream* bcs, VerificationType ref_class_type,
+ RawBytecodeStream* bcs, u2 ref_index, VerificationType ref_class_type,
StackMapFrame* current_frame, u4 code_length, bool* this_uninit,
constantPoolHandle cp, TRAPS);
@@ -147,10 +307,11 @@
constantPoolHandle cp, TRAPS);
VerificationType get_newarray_type(u2 index, u2 bci, TRAPS);
- void verify_anewarray(
- u2 index, constantPoolHandle cp, StackMapFrame* current_frame, TRAPS);
+ void verify_anewarray(u2 bci, u2 index, constantPoolHandle cp,
+ StackMapFrame* current_frame, TRAPS);
void verify_return_value(
- VerificationType return_type, VerificationType type, u2 offset, TRAPS);
+ VerificationType return_type, VerificationType type, u2 offset,
+ StackMapFrame* current_frame, TRAPS);
void verify_iload (u2 index, StackMapFrame* current_frame, TRAPS);
void verify_lload (u2 index, StackMapFrame* current_frame, TRAPS);
@@ -189,7 +350,7 @@
};
// constructor
- ClassVerifier(instanceKlassHandle klass, char* msg, size_t msg_len, TRAPS);
+ ClassVerifier(instanceKlassHandle klass, TRAPS);
// destructor
~ClassVerifier();
@@ -207,13 +368,17 @@
// Return status modes
Symbol* result() const { return _exception_type; }
bool has_error() const { return result() != NULL; }
+ char* exception_message() {
+ stringStream ss;
+ ss.print(_message);
+ _error_context.details(&ss, _method());
+ return ss.as_string();
+ }
// Called when verify or class format errors are encountered.
// May throw an exception based upon the mode.
- void verify_error(u2 offset, const char* fmt, ...);
- void verify_error(const char* fmt, ...);
+ void verify_error(ErrorContext ctx, const char* fmt, ...);
void class_format_error(const char* fmt, ...);
- void format_error_message(const char* fmt, int offset, va_list args);
klassOop load_class(Symbol* name, TRAPS);
@@ -228,10 +393,11 @@
// their reference counts need to be decrememented when the verifier object
// goes out of scope. Since these symbols escape the scope in which they're
// created, we can't use a TempNewSymbol.
- Symbol* create_temporary_symbol(const Symbol* s, int begin, int end, TRAPS);
+ Symbol* create_temporary_symbol(
+ const Symbol* s, int begin, int end, TRAPS);
Symbol* create_temporary_symbol(const char *s, int length, TRAPS);
- static bool _verify_verbose; // for debugging
+ TypeOrigin ref_ctx(const char* str, TRAPS);
};
inline int ClassVerifier::change_sig_to_verificationType(
--- a/hotspot/src/share/vm/runtime/globals.hpp Mon Aug 06 09:34:40 2012 -0700
+++ b/hotspot/src/share/vm/runtime/globals.hpp Mon Aug 06 15:54:45 2012 -0400
@@ -829,6 +829,9 @@
product(bool, PrintGCApplicationStoppedTime, false, \
"Print the time the application has been stopped") \
\
+ diagnostic(bool, VerboseVerification, false, \
+ "Display detailed verification details") \
+ \
notproduct(uintx, ErrorHandlerTest, 0, \
"If > 0, provokes an error after VM initialization; the value" \
"determines which error to provoke. See test_error_handler()" \
--- a/hotspot/src/share/vm/runtime/relocator.cpp Mon Aug 06 09:34:40 2012 -0700
+++ b/hotspot/src/share/vm/runtime/relocator.cpp Mon Aug 06 15:54:45 2012 -0400
@@ -465,13 +465,12 @@
void Relocator::adjust_stack_map_table(int bci, int delta) {
if (method()->has_stackmap_table()) {
typeArrayOop data = method()->stackmap_data();
- // The data in the array is a classfile representation of the stackmap
- // table attribute, less the initial u2 tag and u4 attribute_length fields.
- stack_map_table_attribute* attr = stack_map_table_attribute::at(
- (address)data->byte_at_addr(0) - (sizeof(u2) + sizeof(u4)));
+ // The data in the array is a classfile representation of the stackmap table
+ stack_map_table* sm_table =
+ stack_map_table::at((address)data->byte_at_addr(0));
- int count = attr->number_of_entries();
- stack_map_frame* frame = attr->entries();
+ int count = sm_table->number_of_entries();
+ stack_map_frame* frame = sm_table->entries();
int bci_iter = -1;
bool offset_adjusted = false; // only need to adjust one offset
@@ -486,7 +485,7 @@
frame->set_offset_delta(new_offset_delta);
} else {
assert(frame->is_same_frame() ||
- frame->is_same_frame_1_stack_item_frame(),
+ frame->is_same_locals_1_stack_item_frame(),
"Frame must be one of the compressed forms");
// The new delta exceeds the capacity of the 'same_frame' or
// 'same_frame_1_stack_item_frame' frame types. We need to
@@ -513,7 +512,7 @@
if (frame->is_same_frame()) {
same_frame_extended::create_at(frame_addr, new_offset_delta);
} else {
- same_frame_1_stack_item_extended::create_at(
+ same_locals_1_stack_item_extended::create_at(
frame_addr, new_offset_delta, NULL);
// the verification_info_type should already be at the right spot
}
--- a/hotspot/src/share/vm/utilities/ostream.cpp Mon Aug 06 09:34:40 2012 -0700
+++ b/hotspot/src/share/vm/utilities/ostream.cpp Mon Aug 06 15:54:45 2012 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2012, 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
@@ -237,8 +237,9 @@
return;
}
-void outputStream::indent() {
+outputStream& outputStream::indent() {
while (_position < _indentation) sp();
+ return *this;
}
void outputStream::print_jlong(jlong value) {
@@ -251,6 +252,47 @@
print(os::julong_format_specifier(), value);
}
+/**
+ * This prints out hex data in a 'windbg' or 'xxd' form, where each line is:
+ * <hex-address>: 8 * <hex-halfword> <ascii translation (optional)>
+ * example:
+ * 0000000: 7f44 4f46 0102 0102 0000 0000 0000 0000 .DOF............
+ * 0000010: 0000 0000 0000 0040 0000 0020 0000 0005 .......@... ....
+ * 0000020: 0000 0000 0000 0040 0000 0000 0000 015d .......@.......]
+ * ...
+ *
+ * indent is applied to each line. Ends with a CR.
+ */
+void outputStream::print_data(void* data, size_t len, bool with_ascii) {
+ size_t limit = (len + 16) / 16 * 16;
+ for (size_t i = 0; i < limit; ++i) {
+ if (i % 16 == 0) {
+ indent().print("%07x:", i);
+ }
+ if (i % 2 == 0) {
+ print(" ");
+ }
+ if (i < len) {
+ print("%02x", ((unsigned char*)data)[i]);
+ } else {
+ print(" ");
+ }
+ if ((i + 1) % 16 == 0) {
+ if (with_ascii) {
+ print(" ");
+ for (size_t j = 0; j < 16; ++j) {
+ size_t idx = i + j - 15;
+ if (idx < len) {
+ char c = ((char*)data)[idx];
+ print("%c", c >= 32 && c <= 126 ? c : '.');
+ }
+ }
+ }
+ print_cr("");
+ }
+ }
+}
+
stringStream::stringStream(size_t initial_size) : outputStream() {
buffer_length = initial_size;
buffer = NEW_RESOURCE_ARRAY(char, buffer_length);
--- a/hotspot/src/share/vm/utilities/ostream.hpp Mon Aug 06 09:34:40 2012 -0700
+++ b/hotspot/src/share/vm/utilities/ostream.hpp Mon Aug 06 15:54:45 2012 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2012, 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
@@ -59,9 +59,11 @@
outputStream(int width, bool has_time_stamps);
// indentation
- void indent();
+ outputStream& indent();
void inc() { _indentation++; };
void dec() { _indentation--; };
+ void inc(int n) { _indentation += n; };
+ void dec(int n) { _indentation -= n; };
int indentation() const { return _indentation; }
void set_indentation(int i) { _indentation = i; }
void fill_to(int col);
@@ -84,6 +86,7 @@
void print_raw(const char* str, int len) { write(str, len); }
void print_raw_cr(const char* str) { write(str, strlen(str)); cr(); }
void print_raw_cr(const char* str, int len){ write(str, len); cr(); }
+ void print_data(void* data, size_t len, bool with_ascii);
void put(char ch);
void sp(int count = 1);
void cr();
@@ -122,6 +125,19 @@
extern outputStream* tty; // tty output
extern outputStream* gclog_or_tty; // stream for gc log if -Xloggc:<f>, or tty
+class streamIndentor : public StackObj {
+ private:
+ outputStream* _str;
+ int _amount;
+
+ public:
+ streamIndentor(outputStream* str, int amt = 2) : _str(str), _amount(amt) {
+ _str->inc(_amount);
+ }
+ ~streamIndentor() { _str->dec(_amount); }
+};
+
+
// advisory locking for the shared tty stream:
class ttyLocker: StackObj {
friend class ttyUnlocker;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/7116786/Test7116786.java Mon Aug 06 15:54:45 2012 -0400
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2012, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test Test7116786
+ * @summary verify that VerifyError messages are as expected
+ * @library testcases.jar
+ * @run main/othervm -Xverify:all Test7116786
+ */
+
+
+/**
+ * This class contains information regarding when a VerifyError is thrown
+ * in the verifier. Most of the data is informational-only, and can be
+ * used to track down where and why VerifyErrors are thrown. As such it
+ * is possible the information may go out-of-date.
+ *
+ * The only fields used for the purpose of testing is the 'caseName' and
+ * the 'message'. The 'caseName' corresponds to a classfile which exhibits
+ * the VerifyError, and the 'message' is a regular expression which we expect
+ * to match the verify error message. If the 'message' doesn't match what
+ * we expect, it warrents investigation to see if we are still triggering
+ * the VerifyError that we expect. It could simply just be that the message
+ * changed, which is fine.
+ *
+ * Some cases are not testable, either because the code is probably unreachable
+ * or the test classfile would be too onerous to create. These cases are
+ * marked with 'testable' == false, and the test runner will skip them.
+ */
+class Case {
+ private String caseName; // Name of the case
+ private String file; // Source file where VerifyError is thrown
+ private String location; // enclosing function or switch case
+ private String description; // What causes this VerifyError
+ private String message; // The VerifyError message used.
+
+ private boolean testable; // Whether this case is testable or not.
+
+ public Case(String caseName, String file, boolean testable,
+ String location, String description, String message) {
+ this.caseName = caseName;
+ this.file = file;
+ this.testable = testable;
+ this.location = location;
+ this.description = description;
+ this.message = message;
+ }
+
+ String getCaseName() { return this.caseName; }
+ String getFile() { return this.file; }
+ String getLocation() { return this.location; }
+ String getDescription() { return this.description; }
+ String getMessage() { return this.message; }
+
+ boolean isTestable() { return this.testable; }
+}
+
+/**
+ * These are the locations in the source code where VerifyErrors are thrown
+ * as of today, 2012/07/18. These may change as the verification code is
+ * modified, which is ok. This test is trying to provide coverage for all
+ * VerifyErrors (just to make sure there are no crashes) and it's probably
+ * not necessary to update it every time the VM changes.
+ */
+class VerifyErrorCases {
+ public static final Case[] cases = {
+
+ new Case("case00", "stackMapFrame.cpp", true, "pop_stack_ex",
+ "stack underflow",
+ "Operand stack underflow"),
+
+ new Case("case01", "stackMapFrame.cpp", true, "pop_stack_ex",
+ "stack pop not assignable to expected",
+ "Bad type on operand stack"),
+
+ new Case("case02", "stackMapFrame.cpp", true, "get_local",
+ "local index out-of-bounds",
+ "Local variable table overflow"),
+
+ new Case("case03", "stackMapFrame.cpp", true, "get_local",
+ "local not assignable to expected",
+ "Bad local variable type"),
+
+ new Case("case04", "stackMapFrame.cpp", true, "get_local_2",
+ "local index out-of-bounds [type2]",
+ "get long/double overflows locals"),
+
+ new Case("case05", "stackMapFrame.cpp", true, "get_local_2",
+ "local not assignabled to expected [type2]",
+ "Bad local variable type"),
+
+ /* Unreachable: Can't split long/double on stack */
+ new Case("case06", "stackMapFrame.cpp", false, "get_local_2",
+ "local second-word not assignabled to expected",
+ "Bad local variable type"),
+
+ new Case("case07", "stackMapFrame.cpp", true, "set_local",
+ "local index out-of-bounds",
+ "Local variable table overflow"),
+
+ new Case("case08", "stackMapFrame.cpp", true, "set_local_2",
+ "local index out-of-bounds [type2]",
+ "Local variable table overflow"),
+
+ new Case("case09", "stackMapFrame.hpp", true, "push_stack",
+ "stack overflow",
+ "Operand stack overflow"),
+
+ new Case("case10", "stackMapFrame.hpp", true, "push_stack_2",
+ "stack overflow [type2]",
+ "Operand stack overflow"),
+
+ new Case("case11", "stackMapFrame.hpp", true, "pop_stack",
+ "stack underflow",
+ "Operand stack underflow"),
+
+ new Case("case12", "stackMapTable.cpp", true, "StackMapTable ctor",
+ "stackmap offset beyond code size",
+ "StackMapTable error: bad offset"),
+
+ new Case("case13", "stackMapTable.cpp", true, "match_stackmap",
+ "no stackmap frame at expected location",
+ "Expecting a stackmap frame at branch target "),
+
+ new Case("case14", "stackMapTable.cpp", true, "check_jump_target",
+ "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",
+ "Uninitialized object exists on backward branch "),
+
+ /* Unreachable: wide instructions verified during bytecode analysis */
+ new Case("case16", "verifier.cpp", false, "loop header",
+ "bad op in wide instruction",
+ "Bad wide instruction"),
+
+ new Case("case17", "verifier.cpp", true, "case iaload",
+ "TOS not X array",
+ "Bad type on operand stack in iaload"),
+
+ new Case("case18", "verifier.cpp", true, "case baload",
+ "TOS not X array",
+ "Bad type on operand stack in baload"),
+
+ new Case("case19", "verifier.cpp", true, "case caload",
+ "TOS not X array",
+ "Bad type on operand stack in caload"),
+
+ new Case("case20", "verifier.cpp", true, "case saload",
+ "TOS not X array",
+ "Bad type on operand stack in saload"),
+
+ new Case("case21", "verifier.cpp", true, "case laload",
+ "TOS not X array",
+ "Bad type on operand stack in laload"),
+
+ new Case("case22", "verifier.cpp", true, "case faload",
+ "TOS not X array",
+ "Bad type on operand stack in faload"),
+
+ new Case("case23", "verifier.cpp", true, "case daload",
+ "TOS not X array",
+ "Bad type on operand stack in daload"),
+
+ new Case("case24", "verifier.cpp", true, "case aaload",
+ "TOS not X array",
+ "Bad type on operand stack in aaload"),
+
+ new Case("case25", "verifier.cpp", true, "case iastore",
+ "TOS not int array",
+ "Bad type on operand stack in iastore"),
+
+ new Case("case26", "verifier.cpp", true, "case bastore",
+ "TOS not byte array",
+ "Bad type on operand stack in bastore"),
+
+ new Case("case27", "verifier.cpp", true, "case castore",
+ "TOS not char array",
+ "Bad type on operand stack in castore"),
+
+ new Case("case28", "verifier.cpp", true, "case sastore",
+ "TOS not short array",
+ "Bad type on operand stack in sastore"),
+
+ new Case("case29", "verifier.cpp", true, "case lastore",
+ "TOS not long array",
+ "Bad type on operand stack in lastore"),
+
+ new Case("case30", "verifier.cpp", true, "case fastore",
+ "TOS not float array",
+ "Bad type on operand stack in fastore"),
+
+ new Case("case31", "verifier.cpp", true, "case dastore",
+ "TOS not double array",
+ "Bad type on operand stack in dastore"),
+
+ new Case("case32", "verifier.cpp", true, "case aastore",
+ "TOS not object array",
+ "Bad type on operand stack in aastore"),
+
+ /* Unreachable: In order to hit this case, we would need a
+ * category2_1st at TOS which is not possible. */
+ new Case("case33", "verifier.cpp", false, "case pop2",
+ "TOS is category2_1st (would split)",
+ "Bad type on operand stack in pop2"),
+
+ /* Unreachable: In order to hit this case, we would need a
+ * category2_1st at stack depth 2 with category_1 on TOS which is not
+ * possible. */
+ new Case("case34", "verifier.cpp", false, "case dup_x2",
+ "TOS-1 is category2_1st (would split)",
+ "Bad type on operand stack in dup_x2"),
+
+ /* Unreachable: In order to hit this case, we would need a
+ * category2_1st at TOS which is not possible. */
+ new Case("case35", "verifier.cpp", false, "case dup2",
+ "TOS-1 is category2_1st (would split)",
+ "Bad type on operand stack in dup2"),
+
+ /* Unreachable: In order to hit this case, we would need a
+ * category2_1st at TOS which is not possible. */
+ new Case("case36", "verifier.cpp", false, "case dup2_x1",
+ "TOS-1 is category2_1st (would split)",
+ "Bad type on operand stack in dup2_x1"),
+
+ /* Unreachable: In order to hit this case, we would need a
+ * category2_1st at TOS which is not possible. */
+ new Case("case37", "verifier.cpp", false, "case dup2_x2",
+ "TOS-1 is category2_1st (would split)",
+ "Bad type on operand stack in dup2_x2"),
+
+ /* Unreachable: In order to hit this case, we would need a
+ * category2_1st at stack depth 3 with either 2 category_1 or 1
+ * category_2 on TOS, which is not possible. */
+ new Case("case38", "verifier.cpp", false, "case dup2_x2",
+ "TOS-3 is category2_1st (would split)",
+ "Bad type on operand stack in dup2_x2"),
+
+ new Case("case39", "verifier.cpp", true, "case return",
+ "return type of method is not void",
+ "Method expects a return value"),
+
+ new Case("case40", "verifier.cpp", true, "case return",
+ "return with uninitialized this ",
+ "Constructor must call super() or this() before return"),
+
+ new Case("case41", "verifier.cpp", true, "case new",
+ "cp index not a class type",
+ "Illegal new instruction"),
+
+ new Case("case42", "verifier.cpp", true, "case arraylength",
+ "TOS is not an array",
+ "Bad type on operand stack in arraylength"),
+
+ new Case("case43", "verifier.cpp", true, "case multianewarray",
+ "CP index does not refer to array type",
+ "Illegal constant pool index in multianewarray instruction"),
+
+ new Case("case44", "verifier.cpp", true, "case multianewarray",
+ "Bad dimension (<1) or does not match CP signature",
+ "Illegal dimension in multianewarray instruction: "),
+
+ new Case("case45", "verifier.cpp", true, "case default",
+ "Unrecognized bytecode",
+ "Bad instruction: "),
+
+ new Case("case46", "verifier.cpp", true, "loop end",
+ "control flow falls off method",
+ "Control flow falls through code end"),
+
+ new Case("case47", "verifier.cpp", true, "generate_code_data",
+ "illegal bytecode via RawBytecodeStream (breakpoint)",
+ "Bad instruction"),
+
+ new Case("case48", "verifier.cpp", true, "generate_code_data",
+ "illegal bytecode via RawBytecodeStream (other illegal)",
+ "Bad instruction"),
+
+ new Case("case49", "verifier.cpp", true,
+ "verify_exception_handler_table",
+ "catch_type is not throwable",
+ "Catch type is not a subclass of Throwable in " +
+ "exception handler "),
+
+ new Case("case50", "verifier.cpp", true, "verify_stackmap_table",
+ "missing a stack map frame @ target location (mid table)",
+ "Expecting a stack map frame"),
+
+ new Case("case51", "verifier.cpp", true, "verify_stackmap_table",
+ "stack map does not match?",
+ "Instruction type does not match stack map"),
+
+ new Case("case52", "verifier.cpp", true, "verify_stackmap_table",
+ "missing a stack map frame @ target location (end of table)",
+ "Expecting a stack map frame"),
+
+ new Case("case53", "verifier.cpp", true,
+ "verify_exception_handler_targets",
+ "stackmap mismatch at exception handler",
+ "Stack map does not match the one at exception handler "),
+
+ new Case("case54", "verifier.cpp", true, "verify_cp_index",
+ "constant pool index is out-of-bounds",
+ "Illegal constant pool index "),
+
+ new Case("case55", "verifier.cpp", true, "verify_cp_type",
+ "constant pool entry is not expected type",
+ "Illegal type at constant pool entry "),
+
+ new Case("case56", "verifier.cpp", true, "verify_cp_class_type",
+ "constant pool entry is not an object type",
+ "Illegal type at constant pool entry "),
+
+ /* Unreachable: verify_cp_type gates this case */
+ new Case("case57", "verifier.cpp", false, "verify_ldc",
+ "invalid constant pool index in ldc",
+ "Invalid index in ldc"),
+
+ new Case("case58", "verifier.cpp", true, "verify_switch",
+ "bad switch padding",
+ "Nonzero padding byte in lookswitch or tableswitch"),
+
+ new Case("case59", "verifier.cpp", true, "verify_switch",
+ "tableswitch low is greater than high",
+ "low must be less than or equal to high in tableswitch"),
+
+ /* Unreachable on 64-bit? Only way to get here is to overflow
+ * the 'keys' variable which can't happen on 64-bit since we're dealing
+ * with 32-bit values. Perhaps reachable on 32-bit but the
+ * triggering class would be quite large */
+ new Case("case60", "verifier.cpp", false, "verify_switch",
+ "high - low + 1 < 0 (overflow?)",
+ "too many keys in tableswitch"),
+
+ /* Would have to create a 16G classfile to trip this. Possible but
+ * not reasonable to do in a test. */
+ new Case("case61", "verifier.cpp", false, "verify_switch",
+ "lookupswitch keys < 0",
+ "number of keys in lookupswitch less than 0"),
+
+ new Case("case62", "verifier.cpp", true, "verify_switch",
+ "lookupswitch keys out-of-order",
+ "Bad lookupswitch instruction"),
+
+ /* Unreachable: Class file parser verifies Fieldref contents */
+ new Case("case63", "verifier.cpp", false, "verify_field_instructions",
+ "referenced class is not an CP object",
+ "Expecting reference to class in class "),
+
+ new Case("case64", "verifier.cpp", true, "verify_field_instructions",
+ "TOS not assignable to field type in putfield",
+ "Bad type on operand stack in putfield"),
+
+ new Case("case65", "verifier.cpp", true, "verify_field_instructions",
+ "TOS not assignable to class when accessing protected field",
+ "Bad access to protected data in getfield"),
+
+ new Case("case66", "verifier.cpp", true, "verify_invoke_init",
+ "Uninit_this is not of the current type or it's supertype",
+ "Bad <init> method call"),
+
+ /* Unreachable: Stack map parsing ensures valid type and new
+ * instructions have a valid BCI. */
+ new Case("case67", "verifier.cpp", false, "verify_invoke_init",
+ "Uninit type with bad new instruction index",
+ "Expecting new instruction"),
+
+ new Case("case68", "verifier.cpp", true, "verify_invoke_init",
+ "calling other class's <init> method",
+ "Call to wrong <init> method"),
+
+ new Case("case69", "verifier.cpp", true, "verify_invoke_init",
+ "Calling protected <init> and type unassignable from current",
+ "Bad access to protected <init> method"),
+
+ new Case("case70", "verifier.cpp", true, "verify_invoke_init",
+ "TOS is not an uninitialized (or Uninit_this) type",
+ "Bad operand type when invoking <init>"),
+
+ new Case("case71", "verifier.cpp", true, "verify_invoke_instructions",
+ "Arg count in instruction doesn't match signature",
+ "Inconsistent args count operand in invokeinterface"),
+
+ new Case("case72", "verifier.cpp", true, "verify_invoke_instructions",
+ "Non-zero pad in invokeinterface",
+ "Fourth operand byte of invokeinterface must be zero"),
+
+ new Case("case73", "verifier.cpp", true, "verify_invoke_instructions",
+ "Non-zero pad in invokedynamic",
+ "Third and fourth operand bytes of " +
+ "invokedynamic must be zero"),
+
+ new Case("case74", "verifier.cpp", true, "verify_invoke_instructions",
+ "Non-invokespecial trying to invoke a '<' method",
+ "Illegal call to internal method"),
+
+ new Case("case75", "verifier.cpp", true, "verify_invoke_instructions",
+ "invokespecial and current unassignable from referenced type",
+ "Bad invokespecial instruction: current class isn't " +
+ "assignable to reference class."),
+
+ new Case("case76", "verifier.cpp", true, "verify_invoke_instructions",
+ "TOS not assignable to current when calling protected method",
+ "Bad access to protected data in invokevirtual"),
+
+ /* Unreachable: class file parser enforces void signature */
+ new Case("case77", "verifier.cpp", false, "verify_invoke_instructions",
+ "<init> method is not void return",
+ "Return type must be void in <init> method"),
+
+ new Case("case78", "verifier.cpp", true, "get_newarray_type",
+ "newarray type invalid",
+ "Illegal newarray instruction"),
+
+ new Case("case79", "verifier.cpp", true, "verify_return_value",
+ "void return from method which has a return value",
+ "Method expects a return value"),
+
+ new Case("case80", "verifier.cpp", true, "verify_return_value",
+ "TOS type does not match signature",
+ "Bad return type"),
+
+ new Case("case81", "verifier.cpp", true, "verify_stackmap_table",
+ "stack map does not match (flags)",
+ "Instruction type does not match stack map")
+ };
+}
+
+public class Test7116786 {
+ public static void main(String argv[]) throws Exception {
+ for (Case c : VerifyErrorCases.cases) {
+ System.out.println("******** " + c.getCaseName() + " ********");
+ if (c.isTestable()) {
+ try {
+ ClassLoader cl = Test7116786.class.getClassLoader();
+ Class<?> cls = Class.forName(c.getCaseName(), true, cl);
+ throw new RuntimeException(
+ "++ FAIL: No verify error encountered");
+ } catch (VerifyError ve) {
+ String message = c.getMessage();
+ String veMessage = ve.getMessage();
+ System.out.print(veMessage);
+ if (!veMessage.startsWith(message)) {
+ // We're not seeing the message we expect. Could be
+ // that we've gotten the wrong VerifyError case, or
+ // maybe the message changed.
+ System.out.println("++ FAIL? " +
+ "Message does not match what was expected: " +
+ message);
+ continue;
+ }
+ if (!veMessage.contains("Exception Details:") &&
+ !veMessage.contains("Reason:")) {
+ System.out.println("++ FAIL: No details found");
+ throw new RuntimeException("FAIL: No details found");
+ }
+ System.out.println("++ PASS");
+ }
+ } else {
+ System.out.println("++ SKIPPED");
+ }
+ }
+ }
+}
Binary file hotspot/test/runtime/7116786/testcases.jar has changed