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 }