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