1 /* 2 * Copyright (c) 2022, 2024, 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 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 void check_end() { 171 if (!_stream.at_end()) { 172 _verifier.classError("wrong attribute size"); 173 } 174 } 175 176 private final VerifierImpl _verifier; 177 178 public StackMapReader(byte[] stackmapData, byte[] code_data, int code_len, VerificationWrapper.ConstantPoolWrapper cp, VerifierImpl context) { 179 this._verifier = context; 180 _stream = new StackMapStream(stackmapData, _verifier); 181 if (stackmapData != null) { 182 _frame_count = _stream.get_u2(); 183 } else { 184 _frame_count = 0; 185 } 186 _code_data = code_data; 187 _code_length = code_len; 188 _cp = cp; 189 } 190 191 int chop(VerificationType[] locals, int length, int chops) { 192 if (locals == null) return -1; 193 int pos = length - 1; 194 for (int i=0; i<chops; i++) { 195 if (locals[pos].is_category2_2nd()) { 196 pos -= 2; 197 } else { 198 pos--; 199 } 200 if (pos<0 && i<(chops-1)) return -1; 201 } 202 return pos+1; 203 } 204 205 VerificationType parse_verification_type(int[] flags) { 206 int tag = _stream.get_u1(); 207 if (tag < ITEM_UninitializedThis) { 208 return VerificationType.from_tag(tag, _verifier); 209 } 210 if (tag == ITEM_Object) { 211 int class_index = _stream.get_u2(); 212 int nconstants = _cp.entryCount(); 213 if (class_index <= 0 || class_index >= nconstants || _cp.tagAt(class_index) != VerifierImpl.JVM_CONSTANT_Class) { 214 _verifier.classError("bad class index"); 215 } 216 return VerificationType.reference_type(_cp.classNameAt(class_index)); 217 } 218 if (tag == ITEM_UninitializedThis) { 219 if (flags != null) { 220 flags[0] |= VerificationFrame.FLAG_THIS_UNINIT; 221 } 222 return VerificationType.uninitialized_this_type; 223 } 224 if (tag == ITEM_Uninitialized) { 225 int offset = _stream.get_u2(); 226 if (offset >= _code_length || _code_data[offset] != VerifierImpl.NEW_OFFSET) { 227 _verifier.classError("StackMapTable format error: bad offset for Uninitialized"); 228 } 229 return VerificationType.uninitialized_type(offset); 230 } 231 _verifier.classError("bad verification type"); 232 return VerificationType.bogus_type; 233 } 234 235 public VerificationFrame next(VerificationFrame pre_frame, boolean first, int max_locals, int max_stack) { 236 VerificationFrame frame; 237 int offset; 238 VerificationType[] locals = null; 239 int frame_type = _stream.get_u1(); 240 if (frame_type < 64) { 241 if (first) { 242 offset = frame_type; 243 if (pre_frame.locals_size() > 0) { 244 locals = new VerificationType[pre_frame.locals_size()]; 245 } 246 } else { 247 offset = pre_frame.offset() + frame_type + 1; 248 locals = pre_frame.locals(); 249 } 250 frame = new VerificationFrame(offset, pre_frame.flags(), pre_frame.locals_size(), 0, max_locals, max_stack, locals, null, _verifier); 251 if (first && locals != null) { 252 frame.copy_locals(pre_frame); 253 } 254 return frame; 255 } 256 if (frame_type < 128) { 257 if (first) { 258 offset = frame_type - 64; 259 if (pre_frame.locals_size() > 0) { 260 locals = new VerificationType[pre_frame.locals_size()]; 261 } 262 } else { 263 offset = pre_frame.offset() + frame_type - 63; 264 locals = pre_frame.locals(); 265 } 266 VerificationType[] stack = new VerificationType[2]; 267 int stack_size = 1; 268 stack[0] = parse_verification_type(null); 269 if (stack[0].is_category2()) { 270 stack[1] = stack[0].to_category2_2nd(_verifier); 271 stack_size = 2; 272 } 273 check_verification_type_array_size(stack_size, max_stack); 274 frame = new VerificationFrame(offset, pre_frame.flags(), pre_frame.locals_size(), stack_size, max_locals, max_stack, locals, stack, _verifier); 275 if (first && locals != null) { 276 frame.copy_locals(pre_frame); 277 } 278 return frame; 279 } 280 int offset_delta = _stream.get_u2(); 281 if (frame_type < SAME_LOCALS_1_STACK_ITEM_EXTENDED) { 282 _verifier.classError("reserved frame type"); 283 } 284 if (frame_type == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { 285 if (first) { 286 offset = offset_delta; 287 if (pre_frame.locals_size() > 0) { 288 locals = new VerificationType[pre_frame.locals_size()]; 289 } 290 } else { 291 offset = pre_frame.offset() + offset_delta + 1; 292 locals = pre_frame.locals(); 293 } 294 VerificationType[] stack = new VerificationType[2]; 295 int stack_size = 1; 296 stack[0] = parse_verification_type(null); 297 if (stack[0].is_category2()) { 298 stack[1] = stack[0].to_category2_2nd(_verifier); 299 stack_size = 2; 300 } 301 check_verification_type_array_size(stack_size, max_stack); 302 frame = new VerificationFrame(offset, pre_frame.flags(), pre_frame.locals_size(), stack_size, max_locals, max_stack, locals, stack, _verifier); 303 if (first && locals != null) { 304 frame.copy_locals(pre_frame); 305 } 306 return frame; 307 } 308 if (frame_type <= SAME_EXTENDED) { 309 locals = pre_frame.locals(); 310 int length = pre_frame.locals_size(); 311 int chops = SAME_EXTENDED - frame_type; 312 int new_length = length; 313 int flags = pre_frame.flags(); 314 if (chops != 0) { 315 new_length = chop(locals, length, chops); 316 check_verification_type_array_size(new_length, max_locals); 317 flags = 0; 318 for (int i=0; i<new_length; i++) { 319 if (locals[i].is_uninitialized_this(_verifier)) { 320 flags |= VerificationFrame.FLAG_THIS_UNINIT; 321 break; 322 } 323 } 324 } 325 if (first) { 326 offset = offset_delta; 327 if (new_length > 0) { 328 locals = new VerificationType[new_length]; 329 } else { 330 locals = null; 331 } 332 } else { 333 offset = pre_frame.offset() + offset_delta + 1; 334 } 335 frame = new VerificationFrame(offset, flags, new_length, 0, max_locals, max_stack, locals, null, _verifier); 336 if (first && locals != null) { 337 frame.copy_locals(pre_frame); 338 } 339 return frame; 340 } else if (frame_type < SAME_EXTENDED + 4) { 341 int appends = frame_type - SAME_EXTENDED; 342 int real_length = pre_frame.locals_size(); 343 int new_length = real_length + appends*2; 344 locals = new VerificationType[new_length]; 345 VerificationType[] pre_locals = pre_frame.locals(); 346 int i; 347 for (i=0; i<pre_frame.locals_size(); i++) { 348 locals[i] = pre_locals[i]; 349 } 350 int[] flags = new int[]{pre_frame.flags()}; 351 for (i=0; i<appends; i++) { 352 locals[real_length] = parse_verification_type(flags); 353 if (locals[real_length].is_category2()) { 354 locals[real_length + 1] = locals[real_length].to_category2_2nd(_verifier); 355 ++real_length; 356 } 357 ++real_length; 358 } 359 check_verification_type_array_size(real_length, max_locals); 360 if (first) { 361 offset = offset_delta; 362 } else { 363 offset = pre_frame.offset() + offset_delta + 1; 364 } 365 frame = new VerificationFrame(offset, flags[0], real_length, 0, max_locals, max_stack, locals, null, _verifier); 366 return frame; 367 } 368 if (frame_type == FULL) { 369 int flags[] = new int[]{0}; 370 int locals_size = _stream.get_u2(); 371 int real_locals_size = 0; 372 if (locals_size > 0) { 373 locals = new VerificationType[locals_size*2]; 374 } 375 int i; 376 for (i=0; i<locals_size; i++) { 377 locals[real_locals_size] = parse_verification_type(flags); 378 if (locals[real_locals_size].is_category2()) { 379 locals[real_locals_size + 1] = 380 locals[real_locals_size].to_category2_2nd(_verifier); 381 ++real_locals_size; 382 } 383 ++real_locals_size; 384 } 385 check_verification_type_array_size(real_locals_size, max_locals); 386 int stack_size = _stream.get_u2(); 387 int real_stack_size = 0; 388 VerificationType[] stack = null; 389 if (stack_size > 0) { 390 stack = new VerificationType[stack_size*2]; 391 } 392 for (i=0; i<stack_size; i++) { 393 stack[real_stack_size] = parse_verification_type(null); 394 if (stack[real_stack_size].is_category2()) { 395 stack[real_stack_size + 1] = stack[real_stack_size].to_category2_2nd(_verifier); 396 ++real_stack_size; 397 } 398 ++real_stack_size; 399 } 400 check_verification_type_array_size(real_stack_size, max_stack); 401 if (first) { 402 offset = offset_delta; 403 } else { 404 offset = pre_frame.offset() + offset_delta + 1; 405 } 406 frame = new VerificationFrame(offset, flags[0], real_locals_size, real_stack_size, max_locals, max_stack, locals, stack, _verifier); 407 return frame; 408 } 409 _verifier.classError("reserved frame type"); 410 return null; 411 } 412 } 413 }