jdk

Форк
0
/
stackMapTable.cpp 
436 строк · 15.1 Кб
1
/*
2
 * Copyright (c) 2003, 2023, 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.
8
 *
9
 * This code is distributed in the hope that it will be useful, but WITHOUT
10
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
 * version 2 for more details (a copy is included in the LICENSE file that
13
 * accompanied this code).
14
 *
15
 * You should have received a copy of the GNU General Public License version
16
 * 2 along with this work; if not, write to the Free Software Foundation,
17
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
 *
19
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
 * or visit www.oracle.com if you need additional information or have any
21
 * questions.
22
 *
23
 */
24

25
#include "precompiled.hpp"
26
#include "classfile/stackMapTable.hpp"
27
#include "classfile/verifier.hpp"
28
#include "memory/resourceArea.hpp"
29
#include "oops/constantPool.hpp"
30
#include "oops/oop.inline.hpp"
31
#include "runtime/handles.inline.hpp"
32

33
StackMapTable::StackMapTable(StackMapReader* reader, StackMapFrame* init_frame,
34
                             u2 max_locals, u2 max_stack,
35
                             char* code_data, int code_len, TRAPS) {
36
  _code_length = code_len;
37
  _frame_count = reader->get_frame_count();
38
  if (_frame_count > 0) {
39
    _frame_array = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD,
40
                                                StackMapFrame*, _frame_count);
41
    StackMapFrame* pre_frame = init_frame;
42
    for (int32_t i = 0; i < _frame_count; i++) {
43
      StackMapFrame* frame = reader->next(
44
        pre_frame, i == 0, max_locals, max_stack,
45
        CHECK_VERIFY(pre_frame->verifier()));
46
      _frame_array[i] = frame;
47
      int offset = frame->offset();
48
      if (offset >= code_len || code_data[offset] == 0) {
49
        frame->verifier()->verify_error(
50
            ErrorContext::bad_stackmap(i, frame),
51
            "StackMapTable error: bad offset");
52
        return;
53
      }
54
      pre_frame = frame;
55
    }
56
  }
57
  reader->check_end(CHECK);
58
}
59

60
// This method is only called by method in StackMapTable.
61
int StackMapTable::get_index_from_offset(int32_t offset) const {
62
  int i = 0;
63
  for (; i < _frame_count; i++) {
64
    if (_frame_array[i]->offset() == offset) {
65
      return i;
66
    }
67
  }
68
  return i;  // frame with offset doesn't exist in the array
69
}
70

71
bool StackMapTable::match_stackmap(
72
    StackMapFrame* frame, int32_t target,
73
    bool match, bool update, ErrorContext* ctx, TRAPS) const {
74
  int index = get_index_from_offset(target);
75
  return match_stackmap(frame, target, index, match, update, ctx, THREAD);
76
}
77

78
// Match and/or update current_frame to the frame in stackmap table with
79
// specified offset and frame index. Return true if the two frames match.
80
//
81
// The values of match and update are:                  _match__update
82
//
83
// checking a branch target:                             true   false
84
// checking an exception handler:                        true   false
85
// linear bytecode verification following an
86
// unconditional branch:                                 false  true
87
// linear bytecode verification not following an
88
// unconditional branch:                                 true   true
89
bool StackMapTable::match_stackmap(
90
    StackMapFrame* frame, int32_t target, int32_t frame_index,
91
    bool match, bool update, ErrorContext* ctx, TRAPS) const {
92
  if (frame_index < 0 || frame_index >= _frame_count) {
93
    *ctx = ErrorContext::missing_stackmap(frame->offset());
94
    frame->verifier()->verify_error(
95
        *ctx, "Expecting a stackmap frame at branch target %d", target);
96
    return false;
97
  }
98

99
  StackMapFrame *stackmap_frame = _frame_array[frame_index];
100
  bool result = true;
101
  if (match) {
102
    // Has direct control flow from last instruction, need to match the two
103
    // frames.
104
    result = frame->is_assignable_to(stackmap_frame,
105
        ctx, CHECK_VERIFY_(frame->verifier(), result));
106
  }
107
  if (update) {
108
    // Use the frame in stackmap table as current frame
109
    int lsize = stackmap_frame->locals_size();
110
    int ssize = stackmap_frame->stack_size();
111
    if (frame->locals_size() > lsize || frame->stack_size() > ssize) {
112
      // Make sure unused type array items are all _bogus_type.
113
      frame->reset();
114
    }
115
    frame->set_locals_size(lsize);
116
    frame->copy_locals(stackmap_frame);
117
    frame->set_stack_size(ssize);
118
    frame->copy_stack(stackmap_frame);
119
    frame->set_flags(stackmap_frame->flags());
120
  }
121
  return result;
122
}
123

124
void StackMapTable::check_jump_target(
125
    StackMapFrame* frame, int32_t target, TRAPS) const {
126
  ErrorContext ctx;
127
  bool match = match_stackmap(
128
    frame, target, true, false, &ctx, CHECK_VERIFY(frame->verifier()));
129
  if (!match || (target < 0 || target >= _code_length)) {
130
    frame->verifier()->verify_error(ctx,
131
        "Inconsistent stackmap frames at branch target %d", target);
132
  }
133
}
134

135
void StackMapTable::print_on(outputStream* str) const {
136
  str->indent().print_cr("StackMapTable: frame_count = %d", _frame_count);
137
  str->indent().print_cr("table = { ");
138
  {
139
    streamIndentor si(str);
140
    for (int32_t i = 0; i < _frame_count; ++i) {
141
      _frame_array[i]->print_on(str);
142
    }
143
  }
144
  str->print_cr(" }");
145
}
146

147
StackMapReader::StackMapReader(ClassVerifier* v, StackMapStream* stream, char* code_data,
148
                               int32_t code_len, TRAPS) :
149
                               _verifier(v), _stream(stream),
150
                               _code_data(code_data), _code_length(code_len) {
151
  methodHandle m = v->method();
152
  if (m->has_stackmap_table()) {
153
    _cp = constantPoolHandle(THREAD, m->constants());
154
    _frame_count = _stream->get_u2(CHECK);
155
  } else {
156
    // There's no stackmap table present. Frame count and size are 0.
157
    _frame_count = 0;
158
  }
159
}
160

161
int32_t StackMapReader::chop(
162
    VerificationType* locals, int32_t length, int32_t chops) {
163
  if (locals == nullptr) return -1;
164
  int32_t pos = length - 1;
165
  for (int32_t i=0; i<chops; i++) {
166
    if (locals[pos].is_category2_2nd()) {
167
      pos -= 2;
168
    } else {
169
      pos --;
170
    }
171
    if (pos<0 && i<(chops-1)) return -1;
172
  }
173
  return pos+1;
174
}
175

176
#define CHECK_NT CHECK_(VerificationType::bogus_type())
177

178
VerificationType StackMapReader::parse_verification_type(u1* flags, TRAPS) {
179
  u1 tag = _stream->get_u1(CHECK_NT);
180
  if (tag < (u1)ITEM_UninitializedThis) {
181
    return VerificationType::from_tag(tag);
182
  }
183
  if (tag == ITEM_Object) {
184
    u2 class_index = _stream->get_u2(CHECK_NT);
185
    int nconstants = _cp->length();
186
    if ((class_index <= 0 || class_index >= nconstants) ||
187
        (!_cp->tag_at(class_index).is_klass() &&
188
         !_cp->tag_at(class_index).is_unresolved_klass())) {
189
      _stream->stackmap_format_error("bad class index", THREAD);
190
      return VerificationType::bogus_type();
191
    }
192
    return VerificationType::reference_type(_cp->klass_name_at(class_index));
193
  }
194
  if (tag == ITEM_UninitializedThis) {
195
    if (flags != nullptr) {
196
      *flags |= FLAG_THIS_UNINIT;
197
    }
198
    return VerificationType::uninitialized_this_type();
199
  }
200
  if (tag == ITEM_Uninitialized) {
201
    u2 offset = _stream->get_u2(CHECK_NT);
202
    if (offset >= _code_length ||
203
        _code_data[offset] != ClassVerifier::NEW_OFFSET) {
204
      _verifier->class_format_error(
205
        "StackMapTable format error: bad offset for Uninitialized");
206
      return VerificationType::bogus_type();
207
    }
208
    return VerificationType::uninitialized_type(offset);
209
  }
210
  _stream->stackmap_format_error("bad verification type", THREAD);
211
  return VerificationType::bogus_type();
212
}
213

214
StackMapFrame* StackMapReader::next(
215
    StackMapFrame* pre_frame, bool first, u2 max_locals, u2 max_stack, TRAPS) {
216
  StackMapFrame* frame;
217
  int offset;
218
  VerificationType* locals = nullptr;
219
  u1 frame_type = _stream->get_u1(CHECK_NULL);
220
  if (frame_type < 64) {
221
    // same_frame
222
    if (first) {
223
      offset = frame_type;
224
      // Can't share the locals array since that is updated by the verifier.
225
      if (pre_frame->locals_size() > 0) {
226
        locals = NEW_RESOURCE_ARRAY_IN_THREAD(
227
          THREAD, VerificationType, pre_frame->locals_size());
228
      }
229
    } else {
230
      offset = pre_frame->offset() + frame_type + 1;
231
      locals = pre_frame->locals();
232
    }
233
    frame = new StackMapFrame(
234
      offset, pre_frame->flags(), pre_frame->locals_size(), 0,
235
      max_locals, max_stack, locals, nullptr, _verifier);
236
    if (first && locals != nullptr) {
237
      frame->copy_locals(pre_frame);
238
    }
239
    return frame;
240
  }
241
  if (frame_type < 128) {
242
    // same_locals_1_stack_item_frame
243
    if (first) {
244
      offset = frame_type - 64;
245
      // Can't share the locals array since that is updated by the verifier.
246
      if (pre_frame->locals_size() > 0) {
247
        locals = NEW_RESOURCE_ARRAY_IN_THREAD(
248
          THREAD, VerificationType, pre_frame->locals_size());
249
      }
250
    } else {
251
      offset = pre_frame->offset() + frame_type - 63;
252
      locals = pre_frame->locals();
253
    }
254
    VerificationType* stack = NEW_RESOURCE_ARRAY_IN_THREAD(
255
      THREAD, VerificationType, 2);
256
    u2 stack_size = 1;
257
    stack[0] = parse_verification_type(nullptr, CHECK_VERIFY_(_verifier, nullptr));
258
    if (stack[0].is_category2()) {
259
      stack[1] = stack[0].to_category2_2nd();
260
      stack_size = 2;
261
    }
262
    check_verification_type_array_size(
263
      stack_size, max_stack, CHECK_VERIFY_(_verifier, nullptr));
264
    frame = new StackMapFrame(
265
      offset, pre_frame->flags(), pre_frame->locals_size(), stack_size,
266
      max_locals, max_stack, locals, stack, _verifier);
267
    if (first && locals != nullptr) {
268
      frame->copy_locals(pre_frame);
269
    }
270
    return frame;
271
  }
272

273
  u2 offset_delta = _stream->get_u2(CHECK_NULL);
274

275
  if (frame_type < SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
276
    // reserved frame types
277
    _stream->stackmap_format_error(
278
      "reserved frame type", CHECK_VERIFY_(_verifier, nullptr));
279
  }
280

281
  if (frame_type == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
282
    // same_locals_1_stack_item_frame_extended
283
    if (first) {
284
      offset = offset_delta;
285
      // Can't share the locals array since that is updated by the verifier.
286
      if (pre_frame->locals_size() > 0) {
287
        locals = NEW_RESOURCE_ARRAY_IN_THREAD(
288
          THREAD, 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_RESOURCE_ARRAY_IN_THREAD(
295
      THREAD, VerificationType, 2);
296
    u2 stack_size = 1;
297
    stack[0] = parse_verification_type(nullptr, CHECK_VERIFY_(_verifier, nullptr));
298
    if (stack[0].is_category2()) {
299
      stack[1] = stack[0].to_category2_2nd();
300
      stack_size = 2;
301
    }
302
    check_verification_type_array_size(
303
      stack_size, max_stack, CHECK_VERIFY_(_verifier, nullptr));
304
    frame = new StackMapFrame(
305
      offset, pre_frame->flags(), pre_frame->locals_size(), stack_size,
306
      max_locals, max_stack, locals, stack, _verifier);
307
    if (first && locals != nullptr) {
308
      frame->copy_locals(pre_frame);
309
    }
310
    return frame;
311
  }
312

313
  if (frame_type <= SAME_EXTENDED) {
314
    // chop_frame or same_frame_extended
315
    locals = pre_frame->locals();
316
    int length = pre_frame->locals_size();
317
    int chops = SAME_EXTENDED - frame_type;
318
    int new_length = length;
319
    u1 flags = pre_frame->flags();
320
    if (chops != 0) {
321
      new_length = chop(locals, length, chops);
322
      check_verification_type_array_size(
323
        new_length, max_locals, CHECK_VERIFY_(_verifier, nullptr));
324
      // Recompute flags since uninitializedThis could have been chopped.
325
      flags = 0;
326
      for (int i=0; i<new_length; i++) {
327
        if (locals[i].is_uninitialized_this()) {
328
          flags |= FLAG_THIS_UNINIT;
329
          break;
330
        }
331
      }
332
    }
333
    if (first) {
334
      offset = offset_delta;
335
      // Can't share the locals array since that is updated by the verifier.
336
      if (new_length > 0) {
337
        locals = NEW_RESOURCE_ARRAY_IN_THREAD(
338
          THREAD, VerificationType, new_length);
339
      } else {
340
        locals = nullptr;
341
      }
342
    } else {
343
      offset = pre_frame->offset() + offset_delta + 1;
344
    }
345
    frame = new StackMapFrame(
346
      offset, flags, new_length, 0, max_locals, max_stack,
347
      locals, nullptr, _verifier);
348
    if (first && locals != nullptr) {
349
      frame->copy_locals(pre_frame);
350
    }
351
    return frame;
352
  } else if (frame_type < SAME_EXTENDED + 4) {
353
    // append_frame
354
    int appends = frame_type - SAME_EXTENDED;
355
    int real_length = pre_frame->locals_size();
356
    int new_length = real_length + appends*2;
357
    locals = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, VerificationType, new_length);
358
    VerificationType* pre_locals = pre_frame->locals();
359
    int i;
360
    for (i=0; i<pre_frame->locals_size(); i++) {
361
      locals[i] = pre_locals[i];
362
    }
363
    u1 flags = pre_frame->flags();
364
    for (i=0; i<appends; i++) {
365
      locals[real_length] = parse_verification_type(&flags, CHECK_NULL);
366
      if (locals[real_length].is_category2()) {
367
        locals[real_length + 1] = locals[real_length].to_category2_2nd();
368
        ++real_length;
369
      }
370
      ++real_length;
371
    }
372
    check_verification_type_array_size(
373
      real_length, max_locals, CHECK_VERIFY_(_verifier, nullptr));
374
    if (first) {
375
      offset = offset_delta;
376
    } else {
377
      offset = pre_frame->offset() + offset_delta + 1;
378
    }
379
    frame = new StackMapFrame(
380
      offset, flags, real_length, 0, max_locals,
381
      max_stack, locals, nullptr, _verifier);
382
    return frame;
383
  }
384
  if (frame_type == FULL) {
385
    // full_frame
386
    u1 flags = 0;
387
    u2 locals_size = _stream->get_u2(CHECK_NULL);
388
    int real_locals_size = 0;
389
    if (locals_size > 0) {
390
      locals = NEW_RESOURCE_ARRAY_IN_THREAD(
391
        THREAD, VerificationType, locals_size*2);
392
    }
393
    int i;
394
    for (i=0; i<locals_size; i++) {
395
      locals[real_locals_size] = parse_verification_type(&flags, CHECK_NULL);
396
      if (locals[real_locals_size].is_category2()) {
397
        locals[real_locals_size + 1] =
398
          locals[real_locals_size].to_category2_2nd();
399
        ++real_locals_size;
400
      }
401
      ++real_locals_size;
402
    }
403
    check_verification_type_array_size(
404
      real_locals_size, max_locals, CHECK_VERIFY_(_verifier, nullptr));
405
    u2 stack_size = _stream->get_u2(CHECK_NULL);
406
    int real_stack_size = 0;
407
    VerificationType* stack = nullptr;
408
    if (stack_size > 0) {
409
      stack = NEW_RESOURCE_ARRAY_IN_THREAD(
410
        THREAD, VerificationType, stack_size*2);
411
    }
412
    for (i=0; i<stack_size; i++) {
413
      stack[real_stack_size] = parse_verification_type(nullptr, CHECK_NULL);
414
      if (stack[real_stack_size].is_category2()) {
415
        stack[real_stack_size + 1] = stack[real_stack_size].to_category2_2nd();
416
        ++real_stack_size;
417
      }
418
      ++real_stack_size;
419
    }
420
    check_verification_type_array_size(
421
      real_stack_size, max_stack, CHECK_VERIFY_(_verifier, nullptr));
422
    if (first) {
423
      offset = offset_delta;
424
    } else {
425
      offset = pre_frame->offset() + offset_delta + 1;
426
    }
427
    frame = new StackMapFrame(
428
      offset, flags, real_locals_size, real_stack_size,
429
      max_locals, max_stack, locals, stack, _verifier);
430
    return frame;
431
  }
432

433
  _stream->stackmap_format_error(
434
    "reserved frame type", CHECK_VERIFY_(pre_frame->verifier(), nullptr));
435
  return nullptr;
436
}
437

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.