1 /*
  2  * Copyright (c) 2022, 2024, 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                         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 void check_end() {
171             if (!_stream.at_end()) {
172                 _verifier.classError("wrong attribute size");
173             }
174         }
175 
176         private final VerifierImpl _verifier;
177 
178         public StackMapReader(byte[] stackmapData, byte[] code_data, int code_len, VerificationWrapper.ConstantPoolWrapper cp, VerifierImpl context) {
179             this._verifier = context;
180             _stream = new StackMapStream(stackmapData, _verifier);
181             if (stackmapData != null) {
182                 _frame_count = _stream.get_u2();
183             } else {
184                 _frame_count = 0;
185             }
186             _code_data = code_data;
187             _code_length = code_len;
188             _cp = cp;
189         }
190 
191         int chop(VerificationType[] locals, int length, int chops) {
192             if (locals == null) return -1;
193             int pos = length - 1;
194             for (int i=0; i<chops; i++) {
195                 if (locals[pos].is_category2_2nd()) {
196                     pos -= 2;
197                 } else {
198                     pos--;
199                 }
200                 if (pos<0 && i<(chops-1)) return -1;
201             }
202             return pos+1;
203         }
204 
205         VerificationType parse_verification_type(int[] flags) {
206             int tag = _stream.get_u1();
207             if (tag < ITEM_UninitializedThis) {
208                 return VerificationType.from_tag(tag, _verifier);
209             }
210             if (tag == ITEM_Object) {
211                 int class_index = _stream.get_u2();
212                 int nconstants = _cp.entryCount();
213                 if (class_index <= 0 || class_index >= nconstants || _cp.tagAt(class_index) != VerifierImpl.JVM_CONSTANT_Class) {
214                     _verifier.classError("bad class index");
215                 }
216                 return VerificationType.reference_type(_cp.classNameAt(class_index));
217             }
218             if (tag == ITEM_UninitializedThis) {
219                 if (flags != null) {
220                     flags[0] |= VerificationFrame.FLAG_THIS_UNINIT;
221                 }
222                 return VerificationType.uninitialized_this_type;
223             }
224             if (tag == ITEM_Uninitialized) {
225                 int offset = _stream.get_u2();
226                 if (offset >= _code_length || _code_data[offset] != VerifierImpl.NEW_OFFSET) {
227                     _verifier.classError("StackMapTable format error: bad offset for Uninitialized");
228                 }
229                 return VerificationType.uninitialized_type(offset);
230             }
231             _verifier.classError("bad verification type");
232             return VerificationType.bogus_type;
233         }
234 
235         public VerificationFrame next(VerificationFrame pre_frame, boolean first, int max_locals, int max_stack) {
236             VerificationFrame frame;
237             int offset;
238             VerificationType[] locals = null;
239             int frame_type = _stream.get_u1();
240             if (frame_type < 64) {
241                 if (first) {
242                     offset = frame_type;
243                     if (pre_frame.locals_size() > 0) {
244                         locals = new VerificationType[pre_frame.locals_size()];
245                     }
246                 } else {
247                     offset = pre_frame.offset() + frame_type + 1;
248                     locals = pre_frame.locals();
249                 }
250                 frame = new VerificationFrame(offset, pre_frame.flags(), pre_frame.locals_size(), 0, max_locals, max_stack, locals, null, _verifier);
251                 if (first && locals != null) {
252                     frame.copy_locals(pre_frame);
253                 }
254                 return frame;
255             }
256             if (frame_type < 128) {
257                 if (first) {
258                     offset = frame_type - 64;
259                     if (pre_frame.locals_size() > 0) {
260                         locals = new VerificationType[pre_frame.locals_size()];
261                     }
262                 } else {
263                     offset = pre_frame.offset() + frame_type - 63;
264                     locals = pre_frame.locals();
265                 }
266                 VerificationType[] stack = new VerificationType[2];
267                 int stack_size = 1;
268                 stack[0] = parse_verification_type(null);
269                 if (stack[0].is_category2()) {
270                     stack[1] = stack[0].to_category2_2nd(_verifier);
271                     stack_size = 2;
272                 }
273                 check_verification_type_array_size(stack_size, max_stack);
274                 frame = new VerificationFrame(offset, pre_frame.flags(), pre_frame.locals_size(), stack_size, max_locals, max_stack, locals, stack, _verifier);
275                 if (first && locals != null) {
276                     frame.copy_locals(pre_frame);
277                 }
278                 return frame;
279             }
280             int offset_delta = _stream.get_u2();
281             if (frame_type < SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
282                 _verifier.classError("reserved frame type");
283             }
284             if (frame_type == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
285                 if (first) {
286                     offset = offset_delta;
287                     if (pre_frame.locals_size() > 0) {
288                         locals = new VerificationType[pre_frame.locals_size()];
289                     }
290                 } else {
291                     offset = pre_frame.offset() + offset_delta + 1;
292                     locals = pre_frame.locals();
293                 }
294                 VerificationType[] stack = new VerificationType[2];
295                 int stack_size = 1;
296                 stack[0] = parse_verification_type(null);
297                 if (stack[0].is_category2()) {
298                     stack[1] = stack[0].to_category2_2nd(_verifier);
299                     stack_size = 2;
300                 }
301                 check_verification_type_array_size(stack_size, max_stack);
302                 frame = new VerificationFrame(offset, pre_frame.flags(), pre_frame.locals_size(), stack_size, max_locals, max_stack, locals, stack, _verifier);
303                 if (first && locals != null) {
304                     frame.copy_locals(pre_frame);
305                 }
306                 return frame;
307             }
308             if (frame_type <= SAME_EXTENDED) {
309                 locals = pre_frame.locals();
310                 int length = pre_frame.locals_size();
311                 int chops = SAME_EXTENDED - frame_type;
312                 int new_length = length;
313                 int flags = pre_frame.flags();
314                 if (chops != 0) {
315                     new_length = chop(locals, length, chops);
316                     check_verification_type_array_size(new_length, max_locals);
317                     flags = 0;
318                     for (int i=0; i<new_length; i++) {
319                         if (locals[i].is_uninitialized_this(_verifier)) {
320                             flags |= VerificationFrame.FLAG_THIS_UNINIT;
321                             break;
322                         }
323                     }
324                 }
325                 if (first) {
326                     offset = offset_delta;
327                     if (new_length > 0) {
328                         locals = new VerificationType[new_length];
329                     } else {
330                         locals = null;
331                     }
332                 } else {
333                     offset = pre_frame.offset() + offset_delta + 1;
334                 }
335                 frame = new VerificationFrame(offset, flags, new_length, 0, max_locals, max_stack, locals, null, _verifier);
336                 if (first && locals != null) {
337                     frame.copy_locals(pre_frame);
338                 }
339                 return frame;
340             } else if (frame_type < SAME_EXTENDED + 4) {
341                 int appends = frame_type - SAME_EXTENDED;
342                 int real_length = pre_frame.locals_size();
343                 int new_length = real_length + appends*2;
344                 locals = new VerificationType[new_length];
345                 VerificationType[] pre_locals = pre_frame.locals();
346                 int i;
347                 for (i=0; i<pre_frame.locals_size(); i++) {
348                     locals[i] = pre_locals[i];
349                 }
350                 int[] flags = new int[]{pre_frame.flags()};
351                 for (i=0; i<appends; i++) {
352                     locals[real_length] = parse_verification_type(flags);
353                     if (locals[real_length].is_category2()) {
354                         locals[real_length + 1] = locals[real_length].to_category2_2nd(_verifier);
355                         ++real_length;
356                     }
357                     ++real_length;
358                 }
359                 check_verification_type_array_size(real_length, max_locals);
360                 if (first) {
361                     offset = offset_delta;
362                 } else {
363                     offset = pre_frame.offset() + offset_delta + 1;
364                 }
365                 frame = new VerificationFrame(offset, flags[0], real_length, 0, max_locals, max_stack, locals, null, _verifier);
366                 return frame;
367             }
368             if (frame_type == FULL) {
369                 int flags[] = new int[]{0};
370                 int locals_size = _stream.get_u2();
371                 int real_locals_size = 0;
372                 if (locals_size > 0) {
373                     locals = new VerificationType[locals_size*2];
374                 }
375                 int i;
376                 for (i=0; i<locals_size; i++) {
377                     locals[real_locals_size] = parse_verification_type(flags);
378                     if (locals[real_locals_size].is_category2()) {
379                         locals[real_locals_size + 1] =
380                             locals[real_locals_size].to_category2_2nd(_verifier);
381                         ++real_locals_size;
382                     }
383                     ++real_locals_size;
384                 }
385                 check_verification_type_array_size(real_locals_size, max_locals);
386                 int stack_size = _stream.get_u2();
387                 int real_stack_size = 0;
388                 VerificationType[] stack = null;
389                 if (stack_size > 0) {
390                     stack = new VerificationType[stack_size*2];
391                 }
392                 for (i=0; i<stack_size; i++) {
393                     stack[real_stack_size] = parse_verification_type(null);
394                     if (stack[real_stack_size].is_category2()) {
395                         stack[real_stack_size + 1] = stack[real_stack_size].to_category2_2nd(_verifier);
396                         ++real_stack_size;
397                     }
398                     ++real_stack_size;
399                 }
400                 check_verification_type_array_size(real_stack_size, max_stack);
401                 if (first) {
402                     offset = offset_delta;
403                 } else {
404                     offset = pre_frame.offset() + offset_delta + 1;
405                 }
406                 frame = new VerificationFrame(offset, flags[0], real_locals_size, real_stack_size, max_locals, max_stack, locals, stack, _verifier);
407                 return frame;
408             }
409             _verifier.classError("reserved frame type");
410             return null;
411         }
412     }
413 }