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