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