< prev index next > src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java
Print this page
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.classfile.impl.verifier;
+ import java.lang.classfile.constantpool.NameAndTypeEntry;
import java.util.ArrayList;
+ import java.util.HashSet;
import java.util.List;
+ import java.util.Set;
import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Object;
import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Uninitialized;
import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_UninitializedThis;
frame.set_locals_size(lsize);
frame.copy_locals(stackmap_frame);
frame.set_stack_size(ssize);
frame.copy_stack(stackmap_frame);
frame.set_flags(stackmap_frame.flags());
+ frame.set_assert_unset_fields(stackmap_frame.assert_unset_fields());
}
return result;
}
void check_jump_target(VerificationFrame frame, int target) {
private final int _code_length;
private final int _frame_count;
private int _parsed_frame_count;
private VerificationFrame _prev_frame;
char _max_locals, _max_stack;
+ final Set<NameAndTypeEntry> strictFields;
+ Set<NameAndTypeEntry> _assert_unset_fields_buffer;
boolean _first;
void check_verification_type_array_size(int size, int max_size) {
if (size < 0 || size > max_size) {
_verifier.classError("StackMapTable format error: bad type array size");
}
}
private static final int
+ EARLY_LARVAL = 246,
SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247,
SAME_EXTENDED = 251,
FULL = 255;
+ private static final int RESERVED_TAGS_UPPER_LIMIT = EARLY_LARVAL; // not inclusive
public int get_frame_count() {
return _frame_count;
}
private final VerifierImpl _verifier;
public StackMapReader(byte[] stackmapData, byte[] code_data, int code_len,
VerificationFrame init_frame, char max_locals, char max_stack,
+ Set<NameAndTypeEntry> initial_strict_fields,
VerificationWrapper.ConstantPoolWrapper cp, VerifierImpl context) {
this._verifier = context;
_stream = new StackMapStream(stackmapData, _verifier);
_code_data = code_data;
_code_length = code_len;
_parsed_frame_count = 0;
_prev_frame = init_frame;
_max_locals = max_locals;
_max_stack = max_stack;
+ strictFields = Set.copyOf(initial_strict_fields);
+ _assert_unset_fields_buffer = initial_strict_fields;
_first = true;
if (stackmapData != null) {
_cp = cp;
_frame_count = _stream.get_u2();
} else {
VerificationFrame next_helper() {
VerificationFrame frame;
int offset;
VerificationType[] locals = null;
int frame_type = _stream.get_u1();
if (frame_type < 64) {
if (_first) {
offset = frame_type;
if (_prev_frame.locals_size() > 0) {
locals = new VerificationType[_prev_frame.locals_size()];
}
} else {
offset = _prev_frame.offset() + frame_type + 1;
locals = _prev_frame.locals();
}
! frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), 0, _max_locals, _max_stack, locals, null, _verifier);
if (_first && locals != null) {
frame.copy_locals(_prev_frame);
}
_first = false;
return frame;
VerificationFrame next_helper() {
VerificationFrame frame;
int offset;
VerificationType[] locals = null;
int frame_type = _stream.get_u1();
+ if (frame_type == EARLY_LARVAL) {
+ int num_unset_fields = _stream.get_u2();
+ Set<NameAndTypeEntry> new_fields = new HashSet<>();
+ for (int i = 0; i < num_unset_fields; i++) {
+ int index = _stream.get_u2();
+ if (!_cp.is_within_bounds(index) || _cp.tagAt(index) != VerifierImpl.JVM_CONSTANT_NameAndType) {
+ _prev_frame.verifier().verifyError("Invalid use of strict instance fields %d %s %s".formatted(_prev_frame.offset(), _prev_frame,
+ "Invalid constant pool index in early larval frame: %d".formatted(index)));
+ }
+ var tmp = _cp.cp.entryByIndex(index, NameAndTypeEntry.class);
+ if (!strictFields.contains(tmp)) {
+ _prev_frame.verifier().verifyError("Invalid use of strict instance fields %d %s %s".formatted(_prev_frame.offset(), _prev_frame,
+ "Strict fields not a subset of initial strict instance fields: %s".formatted(tmp)));
+ } else {
+ new_fields.add(tmp);
+ }
+ }
+ // Only modify strict instance fields the frame has uninitialized this
+ if (_prev_frame.flag_this_uninit()) {
+ _assert_unset_fields_buffer = _prev_frame.merge_unset_fields(new_fields);
+ } else if (!new_fields.isEmpty()) {
+ _prev_frame.verifier().verifyError("Invalid use of strict instance fields %d %s %s".formatted(_prev_frame.offset(), _prev_frame,
+ "Cannot have uninitialized strict fields after class initialization"));
+ }
+ // Continue reading frame data
+ if (at_end()) {
+ _prev_frame.verifier().verifyError("Invalid use of strict instance fields %d %s %s".formatted(_prev_frame.offset(), _prev_frame,
+ "Early larval frame must be followed by a base frame"));
+ }
+ frame_type = _stream.get_u1();
+ if (frame_type == EARLY_LARVAL) {
+ _prev_frame.verifier().verifyError("Invalid use of strict instance fields %d %s %s".formatted(_prev_frame.offset(), _prev_frame,
+ "Early larval frame must be followed by a base frame"));
+ }
+ }
if (frame_type < 64) {
if (_first) {
offset = frame_type;
if (_prev_frame.locals_size() > 0) {
locals = new VerificationType[_prev_frame.locals_size()];
}
} else {
offset = _prev_frame.offset() + frame_type + 1;
locals = _prev_frame.locals();
}
! frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), 0, _max_locals, _max_stack, locals, null, _assert_unset_fields_buffer, _verifier);
if (_first && locals != null) {
frame.copy_locals(_prev_frame);
}
_first = false;
return frame;
if (stack[0].is_category2()) {
stack[1] = stack[0].to_category2_2nd(_verifier);
stack_size = 2;
}
check_verification_type_array_size(stack_size, _max_stack);
! frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _verifier);
if (_first && locals != null) {
frame.copy_locals(_prev_frame);
}
_first = false;
return frame;
}
int offset_delta = _stream.get_u2();
! if (frame_type < SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
_verifier.classError("reserved frame type");
}
if (frame_type == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
if (_first) {
offset = offset_delta;
if (stack[0].is_category2()) {
stack[1] = stack[0].to_category2_2nd(_verifier);
stack_size = 2;
}
check_verification_type_array_size(stack_size, _max_stack);
! frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _assert_unset_fields_buffer, _verifier);
if (_first && locals != null) {
frame.copy_locals(_prev_frame);
}
_first = false;
return frame;
}
int offset_delta = _stream.get_u2();
! if (frame_type < RESERVED_TAGS_UPPER_LIMIT) {
_verifier.classError("reserved frame type");
}
if (frame_type == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
if (_first) {
offset = offset_delta;
if (stack[0].is_category2()) {
stack[1] = stack[0].to_category2_2nd(_verifier);
stack_size = 2;
}
check_verification_type_array_size(stack_size, _max_stack);
! frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _verifier);
if (_first && locals != null) {
frame.copy_locals(_prev_frame);
}
_first = false;
return frame;
if (stack[0].is_category2()) {
stack[1] = stack[0].to_category2_2nd(_verifier);
stack_size = 2;
}
check_verification_type_array_size(stack_size, _max_stack);
! frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _assert_unset_fields_buffer, _verifier);
if (_first && locals != null) {
frame.copy_locals(_prev_frame);
}
_first = false;
return frame;
locals = null;
}
} else {
offset = _prev_frame.offset() + offset_delta + 1;
}
! frame = new VerificationFrame(offset, flags, new_length, 0, _max_locals, _max_stack, locals, null, _verifier);
if (_first && locals != null) {
frame.copy_locals(_prev_frame);
}
_first = false;
return frame;
locals = null;
}
} else {
offset = _prev_frame.offset() + offset_delta + 1;
}
! frame = new VerificationFrame(offset, flags, new_length, 0, _max_locals, _max_stack, locals, null, _assert_unset_fields_buffer, _verifier);
if (_first && locals != null) {
frame.copy_locals(_prev_frame);
}
_first = false;
return frame;
if (_first) {
offset = offset_delta;
} else {
offset = _prev_frame.offset() + offset_delta + 1;
}
! frame = new VerificationFrame(offset, flags[0], real_length, 0, _max_locals, _max_stack, locals, null, _verifier);
_first = false;
return frame;
}
if (frame_type == FULL) {
int flags[] = new int[]{0};
if (_first) {
offset = offset_delta;
} else {
offset = _prev_frame.offset() + offset_delta + 1;
}
! frame = new VerificationFrame(offset, flags[0], real_length, 0, _max_locals, _max_stack, locals, null, _assert_unset_fields_buffer, _verifier);
_first = false;
return frame;
}
if (frame_type == FULL) {
int flags[] = new int[]{0};
if (_first) {
offset = offset_delta;
} else {
offset = _prev_frame.offset() + offset_delta + 1;
}
! frame = new VerificationFrame(offset, flags[0], real_locals_size, real_stack_size, _max_locals, _max_stack, locals, stack, _verifier);
_first = false;
return frame;
}
_verifier.classError("reserved frame type");
return null;
if (_first) {
offset = offset_delta;
} else {
offset = _prev_frame.offset() + offset_delta + 1;
}
! frame = new VerificationFrame(offset, flags[0], real_locals_size, real_stack_size, _max_locals, _max_stack, locals, stack, _assert_unset_fields_buffer, _verifier);
_first = false;
return frame;
}
_verifier.classError("reserved frame type");
return null;
< prev index next >