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