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 }