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.util.ArrayList; 28 import java.util.List; 29 30 import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Object; 31 import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Uninitialized; 32 import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_UninitializedThis; 33 34 /// From `stackMapTable.cpp`. 35 class VerificationTable { 36 37 private final int _code_length; 38 private final int _frame_count; 39 private final List<VerificationFrame> _frame_array; 40 private final VerifierImpl _verifier; 41 42 int get_frame_count() { 43 return _frame_count; 44 } 45 46 int get_offset(int index) { 47 return _frame_array.get(index).offset(); 48 } 49 50 static class StackMapStream { 51 52 private final byte[] _data; 53 private int _index; 54 private final VerifierImpl _verifier; 55 56 StackMapStream(byte[] ah, VerifierImpl context) { 57 _data = ah; 58 _index = 0; 59 _verifier = context; 60 } 61 62 int get_u1() { 63 if (_data == null || _index >= _data.length) { 64 _verifier.classError("access beyond the end of attribute"); 65 } 66 return _data[_index++] & 0xff; 67 } 68 69 int get_u2() { 70 int res = get_u1() << 8; 71 return res | get_u1(); 72 } 73 74 boolean at_end() { 75 return (_data == null) || (_index == _data.length); 76 } 77 } 78 79 VerificationTable(StackMapReader reader, 80 VerificationWrapper.ConstantPoolWrapper cp, VerifierImpl v) { 81 _verifier = v; 82 _code_length = reader.code_length(); 83 int _frame_count = reader.get_frame_count(); 84 _frame_array = new ArrayList<>(_frame_count); 85 if (_frame_count > 0) { 86 while (!reader.at_end()) { 87 VerificationFrame frame = reader.next(); 88 if (frame != null) { 89 _frame_array.add(frame); 90 } 91 } 92 } 93 reader.check_end(); 94 this._frame_count = _frame_array.size(); 95 } 96 97 int get_index_from_offset(int offset) { 98 int i = 0; 99 for (; i < _frame_count; i++) { 100 if (_frame_array.get(i).offset() == offset) { 101 return i; 102 } 103 } 104 return i; 105 } 106 107 boolean match_stackmap(VerificationFrame frame, int target, boolean match, boolean update) { 108 int index = get_index_from_offset(target); 109 return match_stackmap(frame, target, index, match, update); 110 } 111 112 boolean match_stackmap(VerificationFrame frame, int target, int frame_index, boolean match, boolean update) { 113 if (frame_index < 0 || frame_index >= _frame_count) { 114 _verifier.verifyError(String.format("Expecting a stackmap frame at branch target %d", target)); 115 } 116 VerificationFrame stackmap_frame = _frame_array.get(frame_index); 117 boolean result = true; 118 if (match) { 119 result = frame.is_assignable_to(stackmap_frame); 120 } 121 if (update) { 122 int lsize = stackmap_frame.locals_size(); 123 int ssize = stackmap_frame.stack_size(); 124 if (frame.locals_size() > lsize || frame.stack_size() > ssize) { 125 frame.reset(); 126 } 127 frame.set_locals_size(lsize); 128 frame.copy_locals(stackmap_frame); 129 frame.set_stack_size(ssize); 130 frame.copy_stack(stackmap_frame); 131 frame.set_flags(stackmap_frame.flags()); 132 } 133 return result; 134 } 135 136 void check_jump_target(VerificationFrame frame, int target) { 137 boolean match = match_stackmap(frame, target, true, false); 138 if (!match || (target < 0 || target >= _code_length)) { 139 _verifier.verifyError(String.format("Inconsistent stackmap frames at branch target %d", target)); 140 } 141 } 142 143 static class StackMapReader { 144 145 private final VerificationWrapper.ConstantPoolWrapper _cp; 146 private final StackMapStream _stream; 147 private final byte[] _code_data; 148 private final int _code_length; 149 private final int _frame_count; 150 private int _parsed_frame_count; 151 private VerificationFrame _prev_frame; 152 char _max_locals, _max_stack; 153 boolean _first; 154 155 void check_verification_type_array_size(int size, int max_size) { 156 if (size < 0 || size > max_size) { 157 _verifier.classError("StackMapTable format error: bad type array size"); 158 } 159 } 160 161 private static final int 162 SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247, 163 SAME_EXTENDED = 251, 164 FULL = 255; 165 166 public int get_frame_count() { 167 return _frame_count; 168 } 169 170 public VerificationFrame prev_frame() { 171 return _prev_frame; 172 } 173 174 public byte[] code_data() { 175 return _code_data; 176 } 177 178 public int code_length() { 179 return _code_length; 180 } 181 182 public boolean at_end() { 183 return _stream.at_end(); 184 } 185 186 public VerificationFrame next() { 187 _parsed_frame_count++; 188 check_size(); 189 VerificationFrame frame = next_helper(); 190 if (frame != null) { 191 check_offset(frame); 192 _prev_frame = frame; 193 } 194 return frame; 195 } 196 197 public void check_end() { 198 if (_frame_count != _parsed_frame_count) { 199 _verifier.verifyError("wrong attribute size"); 200 } 201 } 202 203 private final VerifierImpl _verifier; 204 205 public StackMapReader(byte[] stackmapData, byte[] code_data, int code_len, 206 VerificationFrame init_frame, char max_locals, char max_stack, 207 VerificationWrapper.ConstantPoolWrapper cp, VerifierImpl context) { 208 this._verifier = context; 209 _stream = new StackMapStream(stackmapData, _verifier); 210 _code_data = code_data; 211 _code_length = code_len; 212 _parsed_frame_count = 0; 213 _prev_frame = init_frame; 214 _max_locals = max_locals; 215 _max_stack = max_stack; 216 _first = true; 217 if (stackmapData != null) { 218 _cp = cp; 219 _frame_count = _stream.get_u2(); 220 } else { 221 _cp = null; 222 _frame_count = 0; 223 } 224 } 225 226 void check_offset(VerificationFrame frame) { 227 int offset = frame.offset(); 228 if (offset >= _code_length || _code_data[offset] == 0) { 229 _verifier.verifyError("StackMapTable error: bad offset"); 230 } 231 } 232 233 void check_size() { 234 if (_frame_count < _parsed_frame_count) { 235 _verifier.verifyError("wrong attribute size"); 236 } 237 } 238 239 int chop(VerificationType[] locals, int length, int chops) { 240 if (locals == null) return -1; 241 int pos = length - 1; 242 for (int i=0; i<chops; i++) { 243 if (locals[pos].is_category2_2nd()) { 244 pos -= 2; 245 } else { 246 pos--; 247 } 248 if (pos<0 && i<(chops-1)) return -1; 249 } 250 return pos+1; 251 } 252 253 VerificationType parse_verification_type(int[] flags) { 254 int tag = _stream.get_u1(); 255 if (tag < ITEM_UninitializedThis) { 256 return VerificationType.from_tag(tag, _verifier); 257 } 258 if (tag == ITEM_Object) { 259 int class_index = _stream.get_u2(); 260 int nconstants = _cp.entryCount(); 261 if (class_index <= 0 || class_index >= nconstants || _cp.tagAt(class_index) != VerifierImpl.JVM_CONSTANT_Class) { 262 _verifier.classError("bad class index"); 263 } 264 return VerificationType.reference_type(_cp.classNameAt(class_index)); 265 } 266 if (tag == ITEM_UninitializedThis) { 267 if (flags != null) { 268 flags[0] |= VerificationFrame.FLAG_THIS_UNINIT; 269 } 270 return VerificationType.uninitialized_this_type; 271 } 272 if (tag == ITEM_Uninitialized) { 273 int offset = _stream.get_u2(); 274 if (offset >= _code_length || _code_data[offset] != VerifierImpl.NEW_OFFSET) { 275 _verifier.classError("StackMapTable format error: bad offset for Uninitialized"); 276 } 277 return VerificationType.uninitialized_type(offset); 278 } 279 _verifier.classError("bad verification type"); 280 return VerificationType.bogus_type; 281 } 282 283 VerificationFrame next_helper() { 284 VerificationFrame frame; 285 int offset; 286 VerificationType[] locals = null; 287 int frame_type = _stream.get_u1(); 288 if (frame_type < 64) { 289 if (_first) { 290 offset = frame_type; 291 if (_prev_frame.locals_size() > 0) { 292 locals = new VerificationType[_prev_frame.locals_size()]; 293 } 294 } else { 295 offset = _prev_frame.offset() + frame_type + 1; 296 locals = _prev_frame.locals(); 297 } 298 frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), 0, _max_locals, _max_stack, locals, null, _verifier); 299 if (_first && locals != null) { 300 frame.copy_locals(_prev_frame); 301 } 302 _first = false; 303 return frame; 304 } 305 if (frame_type < 128) { 306 if (_first) { 307 offset = frame_type - 64; 308 if (_prev_frame.locals_size() > 0) { 309 locals = new VerificationType[_prev_frame.locals_size()]; 310 } 311 } else { 312 offset = _prev_frame.offset() + frame_type - 63; 313 locals = _prev_frame.locals(); 314 } 315 VerificationType[] stack = new VerificationType[2]; 316 int stack_size = 1; 317 stack[0] = parse_verification_type(null); 318 if (stack[0].is_category2()) { 319 stack[1] = stack[0].to_category2_2nd(_verifier); 320 stack_size = 2; 321 } 322 check_verification_type_array_size(stack_size, _max_stack); 323 frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _verifier); 324 if (_first && locals != null) { 325 frame.copy_locals(_prev_frame); 326 } 327 _first = false; 328 return frame; 329 } 330 int offset_delta = _stream.get_u2(); 331 if (frame_type < SAME_LOCALS_1_STACK_ITEM_EXTENDED) { 332 _verifier.classError("reserved frame type"); 333 } 334 if (frame_type == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { 335 if (_first) { 336 offset = offset_delta; 337 if (_prev_frame.locals_size() > 0) { 338 locals = new VerificationType[_prev_frame.locals_size()]; 339 } 340 } else { 341 offset = _prev_frame.offset() + offset_delta + 1; 342 locals = _prev_frame.locals(); 343 } 344 VerificationType[] stack = new VerificationType[2]; 345 int stack_size = 1; 346 stack[0] = parse_verification_type(null); 347 if (stack[0].is_category2()) { 348 stack[1] = stack[0].to_category2_2nd(_verifier); 349 stack_size = 2; 350 } 351 check_verification_type_array_size(stack_size, _max_stack); 352 frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _verifier); 353 if (_first && locals != null) { 354 frame.copy_locals(_prev_frame); 355 } 356 _first = false; 357 return frame; 358 } 359 if (frame_type <= SAME_EXTENDED) { 360 locals = _prev_frame.locals(); 361 int length = _prev_frame.locals_size(); 362 int chops = SAME_EXTENDED - frame_type; 363 int new_length = length; 364 int flags = _prev_frame.flags(); 365 if (chops != 0) { 366 new_length = chop(locals, length, chops); 367 check_verification_type_array_size(new_length, _max_locals); 368 flags = 0; 369 for (int i=0; i<new_length; i++) { 370 if (locals[i].is_uninitialized_this(_verifier)) { 371 flags |= VerificationFrame.FLAG_THIS_UNINIT; 372 break; 373 } 374 } 375 } 376 if (_first) { 377 offset = offset_delta; 378 if (new_length > 0) { 379 locals = new VerificationType[new_length]; 380 } else { 381 locals = null; 382 } 383 } else { 384 offset = _prev_frame.offset() + offset_delta + 1; 385 } 386 frame = new VerificationFrame(offset, flags, new_length, 0, _max_locals, _max_stack, locals, null, _verifier); 387 if (_first && locals != null) { 388 frame.copy_locals(_prev_frame); 389 } 390 _first = false; 391 return frame; 392 } else if (frame_type < SAME_EXTENDED + 4) { 393 int appends = frame_type - SAME_EXTENDED; 394 int real_length = _prev_frame.locals_size(); 395 int new_length = real_length + appends*2; 396 locals = new VerificationType[new_length]; 397 VerificationType[] pre_locals = _prev_frame.locals(); 398 int i; 399 for (i=0; i< _prev_frame.locals_size(); i++) { 400 locals[i] = pre_locals[i]; 401 } 402 int[] flags = new int[]{_prev_frame.flags()}; 403 for (i=0; i<appends; i++) { 404 locals[real_length] = parse_verification_type(flags); 405 if (locals[real_length].is_category2()) { 406 locals[real_length + 1] = locals[real_length].to_category2_2nd(_verifier); 407 ++real_length; 408 } 409 ++real_length; 410 } 411 check_verification_type_array_size(real_length, _max_locals); 412 if (_first) { 413 offset = offset_delta; 414 } else { 415 offset = _prev_frame.offset() + offset_delta + 1; 416 } 417 frame = new VerificationFrame(offset, flags[0], real_length, 0, _max_locals, _max_stack, locals, null, _verifier); 418 _first = false; 419 return frame; 420 } 421 if (frame_type == FULL) { 422 int flags[] = new int[]{0}; 423 int locals_size = _stream.get_u2(); 424 int real_locals_size = 0; 425 if (locals_size > 0) { 426 locals = new VerificationType[locals_size*2]; 427 } 428 int i; 429 for (i=0; i<locals_size; i++) { 430 locals[real_locals_size] = parse_verification_type(flags); 431 if (locals[real_locals_size].is_category2()) { 432 locals[real_locals_size + 1] = 433 locals[real_locals_size].to_category2_2nd(_verifier); 434 ++real_locals_size; 435 } 436 ++real_locals_size; 437 } 438 check_verification_type_array_size(real_locals_size, _max_locals); 439 int stack_size = _stream.get_u2(); 440 int real_stack_size = 0; 441 VerificationType[] stack = null; 442 if (stack_size > 0) { 443 stack = new VerificationType[stack_size*2]; 444 } 445 for (i=0; i<stack_size; i++) { 446 stack[real_stack_size] = parse_verification_type(null); 447 if (stack[real_stack_size].is_category2()) { 448 stack[real_stack_size + 1] = stack[real_stack_size].to_category2_2nd(_verifier); 449 ++real_stack_size; 450 } 451 ++real_stack_size; 452 } 453 check_verification_type_array_size(real_stack_size, _max_stack); 454 if (_first) { 455 offset = offset_delta; 456 } else { 457 offset = _prev_frame.offset() + offset_delta + 1; 458 } 459 frame = new VerificationFrame(offset, flags[0], real_locals_size, real_stack_size, _max_locals, _max_stack, locals, stack, _verifier); 460 _first = false; 461 return frame; 462 } 463 _verifier.classError("reserved frame type"); 464 return null; 465 } 466 } 467 }