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 static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Object; 28 import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Uninitialized; 29 import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_UninitializedThis; 30 31 /** 32 * @see <a href="https://raw.githubusercontent.com/openjdk/jdk/master/src/hotspot/share/classfile/stackMapTable.hpp">hotspot/share/classfile/stackMapTable.hpp</a> 33 * @see <a href="https://raw.githubusercontent.com/openjdk/jdk/master/src/hotspot/share/classfile/stackMapTable.cpp">hotspot/share/classfile/stackMapTable.cpp</a> 34 */ 35 class VerificationTable { 36 37 private final int _code_length; 38 private final int _frame_count; 39 private final 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[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(byte[] stackmap_data, VerificationFrame init_frame, int max_locals, int max_stack, byte[] code_data, int code_len, 80 VerificationWrapper.ConstantPoolWrapper cp, VerifierImpl v) { 81 _verifier = v; 82 var reader = new StackMapReader(stackmap_data, code_data, code_len, cp, v); 83 _code_length = code_len; 84 _frame_count = reader.get_frame_count(); 85 _frame_array = new VerificationFrame[_frame_count]; 86 if (_frame_count > 0) { 87 VerificationFrame pre_frame = init_frame; 88 for (int i = 0; i < _frame_count; i++) { 89 VerificationFrame frame = reader.next(pre_frame, i == 0, max_locals, max_stack); 90 _frame_array[i] = frame; 91 int offset = frame.offset(); 92 if (offset >= code_len || code_data[offset] == 0) { 93 _verifier.verifyError("StackMapTable error: bad offset"); 94 } 95 pre_frame = frame; 96 } 97 } 98 reader.check_end(); 99 } 100 101 int get_index_from_offset(int offset) { 102 int i = 0; 103 for (; i < _frame_count; i++) { 104 if (_frame_array[i].offset() == offset) { 105 return i; 106 } 107 } 108 return i; 109 } 110 111 boolean match_stackmap(VerificationFrame frame, int target, boolean match, boolean update) { 112 int index = get_index_from_offset(target); 113 return match_stackmap(frame, target, index, match, update); 114 } 115 116 boolean match_stackmap(VerificationFrame frame, int target, int frame_index, boolean match, boolean update) { 117 if (frame_index < 0 || frame_index >= _frame_count) { 118 _verifier.verifyError(String.format("Expecting a stackmap frame at branch target %d", target)); 119 } 120 VerificationFrame stackmap_frame = _frame_array[frame_index]; 121 boolean result = true; 122 if (match) { 123 result = frame.is_assignable_to(stackmap_frame); 124 } 125 if (update) { 126 int lsize = stackmap_frame.locals_size(); 127 int ssize = stackmap_frame.stack_size(); 128 if (frame.locals_size() > lsize || frame.stack_size() > ssize) { 129 frame.reset(); 130 } 131 frame.set_locals_size(lsize); 132 frame.copy_locals(stackmap_frame); 133 frame.set_stack_size(ssize); 134 frame.copy_stack(stackmap_frame); 135 frame.set_flags(stackmap_frame.flags()); 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 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 ASSERT_UNSET_FIELDS = 246, 163 SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247, 164 SAME_EXTENDED = 251, 165 FULL = 255; 166 private static final int RESERVED_TAGS_UPPER_LIMIT = ASSERT_UNSET_FIELDS; // not inclusive 167 168 public int get_frame_count() { 169 return _frame_count; 170 } 171 172 public void check_end() { 173 if (!_stream.at_end()) { 174 _verifier.classError("wrong attribute size"); 175 } 176 } 177 178 private final VerifierImpl _verifier; 179 180 public StackMapReader(byte[] stackmapData, byte[] code_data, int code_len, VerificationWrapper.ConstantPoolWrapper cp, VerifierImpl context) { 181 this._verifier = context; 182 _stream = new StackMapStream(stackmapData, _verifier); 183 if (stackmapData != null) { 184 _frame_count = _stream.get_u2(); 185 } else { 186 _frame_count = 0; 187 } 188 _code_data = code_data; 189 _code_length = code_len; 190 _cp = cp; 191 } 192 193 int chop(VerificationType[] locals, int length, int chops) { 194 if (locals == null) return -1; 195 int pos = length - 1; 196 for (int i=0; i<chops; i++) { 197 if (locals[pos].is_category2_2nd()) { 198 pos -= 2; 199 } else { 200 pos--; 201 } 202 if (pos<0 && i<(chops-1)) return -1; 203 } 204 return pos+1; 205 } 206 207 VerificationType parse_verification_type(int[] flags) { 208 int tag = _stream.get_u1(); 209 if (tag < ITEM_UninitializedThis) { 210 return VerificationType.from_tag(tag, _verifier); 211 } 212 if (tag == ITEM_Object) { 213 int class_index = _stream.get_u2(); 214 int nconstants = _cp.entryCount(); 215 if (class_index <= 0 || class_index >= nconstants || _cp.tagAt(class_index) != VerifierImpl.JVM_CONSTANT_Class) { 216 _verifier.classError("bad class index"); 217 } 218 return VerificationType.reference_type(_cp.classNameAt(class_index)); 219 } 220 if (tag == ITEM_UninitializedThis) { 221 if (flags != null) { 222 flags[0] |= VerificationFrame.FLAG_THIS_UNINIT; 223 } 224 return VerificationType.uninitialized_this_type; 225 } 226 if (tag == ITEM_Uninitialized) { 227 int offset = _stream.get_u2(); 228 if (offset >= _code_length || _code_data[offset] != VerifierImpl.NEW_OFFSET) { 229 _verifier.classError("StackMapTable format error: bad offset for Uninitialized"); 230 } 231 return VerificationType.uninitialized_type(offset); 232 } 233 _verifier.classError("bad verification type"); 234 return VerificationType.bogus_type; 235 } 236 237 public VerificationFrame next(VerificationFrame pre_frame, boolean first, int max_locals, int max_stack) { 238 VerificationFrame frame; 239 int offset; 240 VerificationType[] locals = null; 241 int frame_type = _stream.get_u1(); 242 if (frame_type < 64) { 243 if (first) { 244 offset = frame_type; 245 if (pre_frame.locals_size() > 0) { 246 locals = new VerificationType[pre_frame.locals_size()]; 247 } 248 } else { 249 offset = pre_frame.offset() + frame_type + 1; 250 locals = pre_frame.locals(); 251 } 252 frame = new VerificationFrame(offset, pre_frame.flags(), pre_frame.locals_size(), 0, max_locals, max_stack, locals, null, _verifier); 253 if (first && locals != null) { 254 frame.copy_locals(pre_frame); 255 } 256 return frame; 257 } 258 if (frame_type < 128) { 259 if (first) { 260 offset = frame_type - 64; 261 if (pre_frame.locals_size() > 0) { 262 locals = new VerificationType[pre_frame.locals_size()]; 263 } 264 } else { 265 offset = pre_frame.offset() + frame_type - 63; 266 locals = pre_frame.locals(); 267 } 268 VerificationType[] stack = new VerificationType[2]; 269 int stack_size = 1; 270 stack[0] = parse_verification_type(null); 271 if (stack[0].is_category2()) { 272 stack[1] = stack[0].to_category2_2nd(_verifier); 273 stack_size = 2; 274 } 275 check_verification_type_array_size(stack_size, max_stack); 276 frame = new VerificationFrame(offset, pre_frame.flags(), pre_frame.locals_size(), stack_size, max_locals, max_stack, locals, stack, _verifier); 277 if (first && locals != null) { 278 frame.copy_locals(pre_frame); 279 } 280 return frame; 281 } 282 int offset_delta = _stream.get_u2(); 283 if (frame_type < RESERVED_TAGS_UPPER_LIMIT) { 284 _verifier.classError("reserved frame type"); 285 } 286 if (frame_type == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { 287 if (first) { 288 offset = offset_delta; 289 if (pre_frame.locals_size() > 0) { 290 locals = new VerificationType[pre_frame.locals_size()]; 291 } 292 } else { 293 offset = pre_frame.offset() + offset_delta + 1; 294 locals = pre_frame.locals(); 295 } 296 VerificationType[] stack = new VerificationType[2]; 297 int stack_size = 1; 298 stack[0] = parse_verification_type(null); 299 if (stack[0].is_category2()) { 300 stack[1] = stack[0].to_category2_2nd(_verifier); 301 stack_size = 2; 302 } 303 check_verification_type_array_size(stack_size, max_stack); 304 frame = new VerificationFrame(offset, pre_frame.flags(), pre_frame.locals_size(), stack_size, max_locals, max_stack, locals, stack, _verifier); 305 if (first && locals != null) { 306 frame.copy_locals(pre_frame); 307 } 308 return frame; 309 } 310 if (frame_type <= SAME_EXTENDED) { 311 locals = pre_frame.locals(); 312 int length = pre_frame.locals_size(); 313 int chops = SAME_EXTENDED - frame_type; 314 int new_length = length; 315 int flags = pre_frame.flags(); 316 if (chops != 0) { 317 new_length = chop(locals, length, chops); 318 check_verification_type_array_size(new_length, max_locals); 319 flags = 0; 320 for (int i=0; i<new_length; i++) { 321 if (locals[i].is_uninitialized_this(_verifier)) { 322 flags |= VerificationFrame.FLAG_THIS_UNINIT; 323 break; 324 } 325 } 326 } 327 if (first) { 328 offset = offset_delta; 329 if (new_length > 0) { 330 locals = new VerificationType[new_length]; 331 } else { 332 locals = null; 333 } 334 } else { 335 offset = pre_frame.offset() + offset_delta + 1; 336 } 337 frame = new VerificationFrame(offset, flags, new_length, 0, max_locals, max_stack, locals, null, _verifier); 338 if (first && locals != null) { 339 frame.copy_locals(pre_frame); 340 } 341 return frame; 342 } else if (frame_type < SAME_EXTENDED + 4) { 343 int appends = frame_type - SAME_EXTENDED; 344 int real_length = pre_frame.locals_size(); 345 int new_length = real_length + appends*2; 346 locals = new VerificationType[new_length]; 347 VerificationType[] pre_locals = pre_frame.locals(); 348 int i; 349 for (i=0; i<pre_frame.locals_size(); i++) { 350 locals[i] = pre_locals[i]; 351 } 352 int[] flags = new int[]{pre_frame.flags()}; 353 for (i=0; i<appends; i++) { 354 locals[real_length] = parse_verification_type(flags); 355 if (locals[real_length].is_category2()) { 356 locals[real_length + 1] = locals[real_length].to_category2_2nd(_verifier); 357 ++real_length; 358 } 359 ++real_length; 360 } 361 check_verification_type_array_size(real_length, max_locals); 362 if (first) { 363 offset = offset_delta; 364 } else { 365 offset = pre_frame.offset() + offset_delta + 1; 366 } 367 frame = new VerificationFrame(offset, flags[0], real_length, 0, max_locals, max_stack, locals, null, _verifier); 368 return frame; 369 } 370 if (frame_type == FULL) { 371 int flags[] = new int[]{0}; 372 int locals_size = _stream.get_u2(); 373 int real_locals_size = 0; 374 if (locals_size > 0) { 375 locals = new VerificationType[locals_size*2]; 376 } 377 int i; 378 for (i=0; i<locals_size; i++) { 379 locals[real_locals_size] = parse_verification_type(flags); 380 if (locals[real_locals_size].is_category2()) { 381 locals[real_locals_size + 1] = 382 locals[real_locals_size].to_category2_2nd(_verifier); 383 ++real_locals_size; 384 } 385 ++real_locals_size; 386 } 387 check_verification_type_array_size(real_locals_size, max_locals); 388 int stack_size = _stream.get_u2(); 389 int real_stack_size = 0; 390 VerificationType[] stack = null; 391 if (stack_size > 0) { 392 stack = new VerificationType[stack_size*2]; 393 } 394 for (i=0; i<stack_size; i++) { 395 stack[real_stack_size] = parse_verification_type(null); 396 if (stack[real_stack_size].is_category2()) { 397 stack[real_stack_size + 1] = stack[real_stack_size].to_category2_2nd(_verifier); 398 ++real_stack_size; 399 } 400 ++real_stack_size; 401 } 402 check_verification_type_array_size(real_stack_size, max_stack); 403 if (first) { 404 offset = offset_delta; 405 } else { 406 offset = pre_frame.offset() + offset_delta + 1; 407 } 408 frame = new VerificationFrame(offset, flags[0], real_locals_size, real_stack_size, max_locals, max_stack, locals, stack, _verifier); 409 return frame; 410 } 411 _verifier.classError("reserved frame type"); 412 return null; 413 } 414 } 415 }