1 /* 2 * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package jdk.internal.classfile.impl.verifier; 26 27 import java.lang.classfile.constantpool.NameAndTypeEntry; 28 import java.util.ArrayList; 29 import java.util.HashSet; 30 import java.util.List; 31 import java.util.Set; 32 33 import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Object; 34 import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Uninitialized; 35 import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_UninitializedThis; 36 37 /// From `stackMapTable.cpp`. 38 class VerificationTable { 39 40 private final int _code_length; 41 private final int _frame_count; 42 private final List<VerificationFrame> _frame_array; 43 private final VerifierImpl _verifier; 44 45 int get_frame_count() { 46 return _frame_count; 47 } 48 49 int get_offset(int index) { 50 return _frame_array.get(index).offset(); 51 } 52 53 static class StackMapStream { 54 55 private final byte[] _data; 56 private int _index; 57 private final VerifierImpl _verifier; 58 59 StackMapStream(byte[] ah, VerifierImpl context) { 60 _data = ah; 61 _index = 0; 62 _verifier = context; 63 } 64 65 int get_u1() { 66 if (_data == null || _index >= _data.length) { 67 _verifier.classError("access beyond the end of attribute"); 68 } 69 return _data[_index++] & 0xff; 70 } 71 72 int get_u2() { 73 int res = get_u1() << 8; 74 return res | get_u1(); 75 } 76 77 boolean at_end() { 78 return (_data == null) || (_index == _data.length); 79 } 80 } 81 82 VerificationTable(StackMapReader reader, 83 VerificationWrapper.ConstantPoolWrapper cp, VerifierImpl v) { 84 _verifier = v; 85 _code_length = reader.code_length(); 86 int _frame_count = reader.get_frame_count(); 87 _frame_array = new ArrayList<>(_frame_count); 88 if (_frame_count > 0) { 89 while (!reader.at_end()) { 90 VerificationFrame frame = reader.next(); 91 if (frame != null) { 92 _frame_array.add(frame); 93 } 94 } 95 } 96 reader.check_end(); 97 this._frame_count = _frame_array.size(); 98 } 99 100 int get_index_from_offset(int offset) { 101 int i = 0; 102 for (; i < _frame_count; i++) { 103 if (_frame_array.get(i).offset() == offset) { 104 return i; 105 } 106 } 107 return i; 108 } 109 110 boolean match_stackmap(VerificationFrame frame, int target, boolean match, boolean update) { 111 int index = get_index_from_offset(target); 112 return match_stackmap(frame, target, index, match, update); 113 } 114 115 boolean match_stackmap(VerificationFrame frame, int target, int frame_index, boolean match, boolean update) { 116 if (frame_index < 0 || frame_index >= _frame_count) { 117 _verifier.verifyError(String.format("Expecting a stackmap frame at branch target %d", target)); 118 } 119 VerificationFrame stackmap_frame = _frame_array.get(frame_index); 120 boolean result = true; 121 if (match) { 122 result = frame.is_assignable_to(stackmap_frame); 123 } 124 if (update) { 125 int lsize = stackmap_frame.locals_size(); 126 int ssize = stackmap_frame.stack_size(); 127 if (frame.locals_size() > lsize || frame.stack_size() > ssize) { 128 frame.reset(); 129 } 130 frame.set_locals_size(lsize); 131 frame.copy_locals(stackmap_frame); 132 frame.set_stack_size(ssize); 133 frame.copy_stack(stackmap_frame); 134 frame.set_flags(stackmap_frame.flags()); 135 frame.set_assert_unset_fields(stackmap_frame.assert_unset_fields()); 136 } 137 return result; 138 } 139 140 void check_jump_target(VerificationFrame frame, int target) { 141 boolean match = match_stackmap(frame, target, true, false); 142 if (!match || (target < 0 || target >= _code_length)) { 143 _verifier.verifyError(String.format("Inconsistent stackmap frames at branch target %d", target)); 144 } 145 } 146 147 static class StackMapReader { 148 149 private final VerificationWrapper.ConstantPoolWrapper _cp; 150 private final StackMapStream _stream; 151 private final byte[] _code_data; 152 private final int _code_length; 153 private final int _frame_count; 154 private int _parsed_frame_count; 155 private VerificationFrame _prev_frame; 156 char _max_locals, _max_stack; 157 final Set<NameAndTypeEntry> strictFields; 158 Set<NameAndTypeEntry> _assert_unset_fields_buffer; 159 boolean _first; 160 161 void check_verification_type_array_size(int size, int max_size) { 162 if (size < 0 || size > max_size) { 163 _verifier.classError("StackMapTable format error: bad type array size"); 164 } 165 } 166 167 private static final int 168 EARLY_LARVAL = 246, 169 SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247, 170 SAME_EXTENDED = 251, 171 FULL = 255; 172 private static final int RESERVED_TAGS_UPPER_LIMIT = EARLY_LARVAL; // not inclusive 173 174 public int get_frame_count() { 175 return _frame_count; 176 } 177 178 public VerificationFrame prev_frame() { 179 return _prev_frame; 180 } 181 182 public byte[] code_data() { 183 return _code_data; 184 } 185 186 public int code_length() { 187 return _code_length; 188 } 189 190 public boolean at_end() { 191 return _stream.at_end(); 192 } 193 194 public VerificationFrame next() { 195 _parsed_frame_count++; 196 check_size(); 197 VerificationFrame frame = next_helper(); 198 if (frame != null) { 199 check_offset(frame); 200 _prev_frame = frame; 201 } 202 return frame; 203 } 204 205 public void check_end() { 206 if (_frame_count != _parsed_frame_count) { 207 _verifier.verifyError("wrong attribute size"); 208 } 209 } 210 211 private final VerifierImpl _verifier; 212 213 public StackMapReader(byte[] stackmapData, byte[] code_data, int code_len, 214 VerificationFrame init_frame, char max_locals, char max_stack, 215 Set<NameAndTypeEntry> initial_strict_fields, 216 VerificationWrapper.ConstantPoolWrapper cp, VerifierImpl context) { 217 this._verifier = context; 218 _stream = new StackMapStream(stackmapData, _verifier); 219 _code_data = code_data; 220 _code_length = code_len; 221 _parsed_frame_count = 0; 222 _prev_frame = init_frame; 223 _max_locals = max_locals; 224 _max_stack = max_stack; 225 strictFields = Set.copyOf(initial_strict_fields); 226 _assert_unset_fields_buffer = initial_strict_fields; 227 _first = true; 228 if (stackmapData != null) { 229 _cp = cp; 230 _frame_count = _stream.get_u2(); 231 } else { 232 _cp = null; 233 _frame_count = 0; 234 } 235 } 236 237 void check_offset(VerificationFrame frame) { 238 int offset = frame.offset(); 239 if (offset >= _code_length || _code_data[offset] == 0) { 240 _verifier.verifyError("StackMapTable error: bad offset"); 241 } 242 } 243 244 void check_size() { 245 if (_frame_count < _parsed_frame_count) { 246 _verifier.verifyError("wrong attribute size"); 247 } 248 } 249 250 int chop(VerificationType[] locals, int length, int chops) { 251 if (locals == null) return -1; 252 int pos = length - 1; 253 for (int i=0; i<chops; i++) { 254 if (locals[pos].is_category2_2nd()) { 255 pos -= 2; 256 } else { 257 pos--; 258 } 259 if (pos<0 && i<(chops-1)) return -1; 260 } 261 return pos+1; 262 } 263 264 VerificationType parse_verification_type(int[] flags) { 265 int tag = _stream.get_u1(); 266 if (tag < ITEM_UninitializedThis) { 267 return VerificationType.from_tag(tag, _verifier); 268 } 269 if (tag == ITEM_Object) { 270 int class_index = _stream.get_u2(); 271 int nconstants = _cp.entryCount(); 272 if (class_index <= 0 || class_index >= nconstants || _cp.tagAt(class_index) != VerifierImpl.JVM_CONSTANT_Class) { 273 _verifier.classError("bad class index"); 274 } 275 return VerificationType.reference_type(_cp.classNameAt(class_index)); 276 } 277 if (tag == ITEM_UninitializedThis) { 278 if (flags != null) { 279 flags[0] |= VerificationFrame.FLAG_THIS_UNINIT; 280 } 281 return VerificationType.uninitialized_this_type; 282 } 283 if (tag == ITEM_Uninitialized) { 284 int offset = _stream.get_u2(); 285 if (offset >= _code_length || _code_data[offset] != VerifierImpl.NEW_OFFSET) { 286 _verifier.classError("StackMapTable format error: bad offset for Uninitialized"); 287 } 288 return VerificationType.uninitialized_type(offset); 289 } 290 _verifier.classError("bad verification type"); 291 return VerificationType.bogus_type; 292 } 293 294 VerificationFrame next_helper() { 295 VerificationFrame frame; 296 int offset; 297 VerificationType[] locals = null; 298 int frame_type = _stream.get_u1(); 299 if (frame_type == EARLY_LARVAL) { 300 int num_unset_fields = _stream.get_u2(); 301 Set<NameAndTypeEntry> new_fields = new HashSet<>(); 302 for (int i = 0; i < num_unset_fields; i++) { 303 int index = _stream.get_u2(); 304 if (!_cp.is_within_bounds(index) || _cp.tagAt(index) != VerifierImpl.JVM_CONSTANT_NameAndType) { 305 _prev_frame.verifier().verifyError("Invalid use of strict instance fields %d %s %s".formatted(_prev_frame.offset(), _prev_frame, 306 "Invalid constant pool index in early larval frame: %d".formatted(index))); 307 } 308 var tmp = _cp.cp.entryByIndex(index, NameAndTypeEntry.class); 309 if (!strictFields.contains(tmp)) { 310 _prev_frame.verifier().verifyError("Invalid use of strict instance fields %d %s %s".formatted(_prev_frame.offset(), _prev_frame, 311 "Strict fields not a subset of initial strict instance fields: %s".formatted(tmp))); 312 } else { 313 new_fields.add(tmp); 314 } 315 } 316 // Only modify strict instance fields the frame has uninitialized this 317 if (_prev_frame.flag_this_uninit()) { 318 _assert_unset_fields_buffer = _prev_frame.merge_unset_fields(new_fields); 319 } else if (!new_fields.isEmpty()) { 320 _prev_frame.verifier().verifyError("Invalid use of strict instance fields %d %s %s".formatted(_prev_frame.offset(), _prev_frame, 321 "Cannot have uninitialized strict fields after class initialization")); 322 } 323 // Continue reading frame data 324 if (at_end()) { 325 _prev_frame.verifier().verifyError("Invalid use of strict instance fields %d %s %s".formatted(_prev_frame.offset(), _prev_frame, 326 "Early larval frame must be followed by a base frame")); 327 } 328 frame_type = _stream.get_u1(); 329 if (frame_type == EARLY_LARVAL) { 330 _prev_frame.verifier().verifyError("Invalid use of strict instance fields %d %s %s".formatted(_prev_frame.offset(), _prev_frame, 331 "Early larval frame must be followed by a base frame")); 332 } 333 } 334 if (frame_type < 64) { 335 if (_first) { 336 offset = frame_type; 337 if (_prev_frame.locals_size() > 0) { 338 locals = new VerificationType[_prev_frame.locals_size()]; 339 } 340 } else { 341 offset = _prev_frame.offset() + frame_type + 1; 342 locals = _prev_frame.locals(); 343 } 344 frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), 0, _max_locals, _max_stack, locals, null, _assert_unset_fields_buffer, _verifier); 345 if (_first && locals != null) { 346 frame.copy_locals(_prev_frame); 347 } 348 _first = false; 349 return frame; 350 } 351 if (frame_type < 128) { 352 if (_first) { 353 offset = frame_type - 64; 354 if (_prev_frame.locals_size() > 0) { 355 locals = new VerificationType[_prev_frame.locals_size()]; 356 } 357 } else { 358 offset = _prev_frame.offset() + frame_type - 63; 359 locals = _prev_frame.locals(); 360 } 361 VerificationType[] stack = new VerificationType[2]; 362 int stack_size = 1; 363 stack[0] = parse_verification_type(null); 364 if (stack[0].is_category2()) { 365 stack[1] = stack[0].to_category2_2nd(_verifier); 366 stack_size = 2; 367 } 368 check_verification_type_array_size(stack_size, _max_stack); 369 frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _assert_unset_fields_buffer, _verifier); 370 if (_first && locals != null) { 371 frame.copy_locals(_prev_frame); 372 } 373 _first = false; 374 return frame; 375 } 376 int offset_delta = _stream.get_u2(); 377 if (frame_type < RESERVED_TAGS_UPPER_LIMIT) { 378 _verifier.classError("reserved frame type"); 379 } 380 if (frame_type == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { 381 if (_first) { 382 offset = offset_delta; 383 if (_prev_frame.locals_size() > 0) { 384 locals = new VerificationType[_prev_frame.locals_size()]; 385 } 386 } else { 387 offset = _prev_frame.offset() + offset_delta + 1; 388 locals = _prev_frame.locals(); 389 } 390 VerificationType[] stack = new VerificationType[2]; 391 int stack_size = 1; 392 stack[0] = parse_verification_type(null); 393 if (stack[0].is_category2()) { 394 stack[1] = stack[0].to_category2_2nd(_verifier); 395 stack_size = 2; 396 } 397 check_verification_type_array_size(stack_size, _max_stack); 398 frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _assert_unset_fields_buffer, _verifier); 399 if (_first && locals != null) { 400 frame.copy_locals(_prev_frame); 401 } 402 _first = false; 403 return frame; 404 } 405 if (frame_type <= SAME_EXTENDED) { 406 locals = _prev_frame.locals(); 407 int length = _prev_frame.locals_size(); 408 int chops = SAME_EXTENDED - frame_type; 409 int new_length = length; 410 int flags = _prev_frame.flags(); 411 if (chops != 0) { 412 new_length = chop(locals, length, chops); 413 check_verification_type_array_size(new_length, _max_locals); 414 flags = 0; 415 for (int i=0; i<new_length; i++) { 416 if (locals[i].is_uninitialized_this(_verifier)) { 417 flags |= VerificationFrame.FLAG_THIS_UNINIT; 418 break; 419 } 420 } 421 } 422 if (_first) { 423 offset = offset_delta; 424 if (new_length > 0) { 425 locals = new VerificationType[new_length]; 426 } else { 427 locals = null; 428 } 429 } else { 430 offset = _prev_frame.offset() + offset_delta + 1; 431 } 432 frame = new VerificationFrame(offset, flags, new_length, 0, _max_locals, _max_stack, locals, null, _assert_unset_fields_buffer, _verifier); 433 if (_first && locals != null) { 434 frame.copy_locals(_prev_frame); 435 } 436 _first = false; 437 return frame; 438 } else if (frame_type < SAME_EXTENDED + 4) { 439 int appends = frame_type - SAME_EXTENDED; 440 int real_length = _prev_frame.locals_size(); 441 int new_length = real_length + appends*2; 442 locals = new VerificationType[new_length]; 443 VerificationType[] pre_locals = _prev_frame.locals(); 444 int i; 445 for (i=0; i< _prev_frame.locals_size(); i++) { 446 locals[i] = pre_locals[i]; 447 } 448 int[] flags = new int[]{_prev_frame.flags()}; 449 for (i=0; i<appends; i++) { 450 locals[real_length] = parse_verification_type(flags); 451 if (locals[real_length].is_category2()) { 452 locals[real_length + 1] = locals[real_length].to_category2_2nd(_verifier); 453 ++real_length; 454 } 455 ++real_length; 456 } 457 check_verification_type_array_size(real_length, _max_locals); 458 if (_first) { 459 offset = offset_delta; 460 } else { 461 offset = _prev_frame.offset() + offset_delta + 1; 462 } 463 frame = new VerificationFrame(offset, flags[0], real_length, 0, _max_locals, _max_stack, locals, null, _assert_unset_fields_buffer, _verifier); 464 _first = false; 465 return frame; 466 } 467 if (frame_type == FULL) { 468 int flags[] = new int[]{0}; 469 int locals_size = _stream.get_u2(); 470 int real_locals_size = 0; 471 if (locals_size > 0) { 472 locals = new VerificationType[locals_size*2]; 473 } 474 int i; 475 for (i=0; i<locals_size; i++) { 476 locals[real_locals_size] = parse_verification_type(flags); 477 if (locals[real_locals_size].is_category2()) { 478 locals[real_locals_size + 1] = 479 locals[real_locals_size].to_category2_2nd(_verifier); 480 ++real_locals_size; 481 } 482 ++real_locals_size; 483 } 484 check_verification_type_array_size(real_locals_size, _max_locals); 485 int stack_size = _stream.get_u2(); 486 int real_stack_size = 0; 487 VerificationType[] stack = null; 488 if (stack_size > 0) { 489 stack = new VerificationType[stack_size*2]; 490 } 491 for (i=0; i<stack_size; i++) { 492 stack[real_stack_size] = parse_verification_type(null); 493 if (stack[real_stack_size].is_category2()) { 494 stack[real_stack_size + 1] = stack[real_stack_size].to_category2_2nd(_verifier); 495 ++real_stack_size; 496 } 497 ++real_stack_size; 498 } 499 check_verification_type_array_size(real_stack_size, _max_stack); 500 if (_first) { 501 offset = offset_delta; 502 } else { 503 offset = _prev_frame.offset() + offset_delta + 1; 504 } 505 frame = new VerificationFrame(offset, flags[0], real_locals_size, real_stack_size, _max_locals, _max_stack, locals, stack, _assert_unset_fields_buffer, _verifier); 506 _first = false; 507 return frame; 508 } 509 _verifier.classError("reserved frame type"); 510 return null; 511 } 512 } 513 }