mirror of
https://gitee.com/openharmony/arkcompiler_runtime_core
synced 2025-04-17 18:10:19 +00:00
!2520 Refactor verifier based on ruby
Merge pull request !2520 from XHQ/refact_ruby
This commit is contained in:
commit
a7d2952aea
@ -17,7 +17,7 @@
|
||||
import os
|
||||
import yaml
|
||||
|
||||
current_version = "13.0.0.0"
|
||||
CURRENT_VERSION = "13.0.0.0"
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
@ -38,4 +38,4 @@ def check_version(yaml_file, cur_version):
|
||||
except Exception as e:
|
||||
print(f"Error reading file: {e}")
|
||||
|
||||
check_version(isa_file_path, current_version)
|
||||
check_version(isa_file_path, CURRENT_VERSION)
|
||||
|
34
isa/isa.yaml
34
isa/isa.yaml
@ -165,6 +165,16 @@ properties:
|
||||
description: The instruction occupies ic slots of 16 bit width.
|
||||
- tag: eight_sixteen_bit_ic
|
||||
description: The instruction occupies ic slots of both 8 and 16 bit width.
|
||||
- tag: conditional_throw
|
||||
description: The throw instruction can throw an excepton only if certain conditions are met.
|
||||
- tag: range_0
|
||||
description: Indicates that the instruction takes some consective registers as inputs.
|
||||
The start register of these consective inputs is the last register of the instruction.
|
||||
The number of consective inputs is the last immediate of the instruction.
|
||||
- tag: range_1
|
||||
description: Indicates that the instruction takes some consective registers as inputs.
|
||||
The start register of these consective inputs is the last register of the instruction.
|
||||
The number of consective inputs is the last immediate of the instruction plus 1.
|
||||
|
||||
exceptions:
|
||||
- tag: x_none
|
||||
@ -475,11 +485,13 @@ groups:
|
||||
acc: out:top
|
||||
opcode_idx: [0xb3]
|
||||
format: [op_imm_8_v1_8_v2_8]
|
||||
properties: [range_1]
|
||||
- sig: wide.createobjectwithexcludedkeys imm:u16, v1:in:top, v2:in:top
|
||||
acc: out:top
|
||||
opcode_idx: [0x00]
|
||||
format: [pref_op_imm_16_v1_8_v2_8]
|
||||
prefix: wide
|
||||
properties: [range_1]
|
||||
- sig: createarraywithbuffer imm:u16, literalarray_id
|
||||
acc: out:top
|
||||
opcode_idx: [0x06, 0x81]
|
||||
@ -514,12 +526,13 @@ groups:
|
||||
acc: out:top
|
||||
opcode_idx: [0x08, 0x83]
|
||||
format: [op_imm1_8_imm2_8_v_8, op_imm1_16_imm2_8_v_8]
|
||||
properties: [ic_slot, two_slot, eight_sixteen_bit_ic]
|
||||
properties: [ic_slot, two_slot, eight_sixteen_bit_ic, range_0]
|
||||
- sig: wide.newobjrange imm:u16, v:in:top
|
||||
acc: out:top
|
||||
opcode_idx: [0x01]
|
||||
format: [pref_op_imm_16_v_8]
|
||||
prefix: wide
|
||||
properties: [range_0]
|
||||
- sig: newlexenv imm:u8
|
||||
acc: out:top
|
||||
opcode_idx: [0x09]
|
||||
@ -971,22 +984,25 @@ groups:
|
||||
opcode_idx: [0x05]
|
||||
format: [pref_op_v_8]
|
||||
prefix: throw
|
||||
properties: [conditional_throw]
|
||||
- sig: throw.undefinedifhole v1:in:top, v2:in:top
|
||||
acc: none
|
||||
opcode_idx: [0x06]
|
||||
format: [pref_op_v1_8_v2_8]
|
||||
prefix: throw
|
||||
properties: [conditional_throw]
|
||||
- sig: throw.ifsupernotcorrectcall imm:u16
|
||||
acc: in:top
|
||||
opcode_idx: [0x07, 0x08]
|
||||
format: [pref_op_imm_8, pref_op_imm_16]
|
||||
prefix: throw
|
||||
properties: [conditional_throw]
|
||||
- sig: throw.undefinedifholewithname string_id
|
||||
acc: in:top
|
||||
opcode_idx: [0x09]
|
||||
format: [pref_op_id_16]
|
||||
prefix: throw
|
||||
properties: [string_id]
|
||||
properties: [string_id, conditional_throw]
|
||||
|
||||
- title: call instructions
|
||||
description: call
|
||||
@ -1047,17 +1063,19 @@ groups:
|
||||
acc: inout:top
|
||||
opcode_idx: [0x73]
|
||||
format: [op_imm1_8_imm2_8_v_8]
|
||||
properties: [jit_ic_slot, two_slot, eight_bit_ic]
|
||||
properties: [jit_ic_slot, two_slot, eight_bit_ic, range_0]
|
||||
- sig: wide.callrange imm:u16, v:in:top
|
||||
acc: inout:top
|
||||
opcode_idx: [0x04]
|
||||
format: [pref_op_imm_16_v_8]
|
||||
prefix: wide
|
||||
properties: [range_0]
|
||||
- sig: deprecated.callrange imm:u16, v:in:top
|
||||
acc: out:top
|
||||
opcode_idx: [0x0f]
|
||||
format: [pref_op_imm_16_v_8]
|
||||
prefix: deprecated
|
||||
properties: [range_0]
|
||||
- sig: supercallspread imm:u8, v:in:top
|
||||
acc: inout:top
|
||||
opcode_idx: [0xb9]
|
||||
@ -1097,37 +1115,41 @@ groups:
|
||||
acc: inout:top
|
||||
opcode_idx: [0x31]
|
||||
format: [op_imm1_8_imm2_8_v_8]
|
||||
properties: [jit_ic_slot, two_slot, eight_bit_ic]
|
||||
properties: [jit_ic_slot, two_slot, eight_bit_ic, range_0]
|
||||
- sig: wide.callthisrange imm:u16, v:in:top
|
||||
acc: inout:top
|
||||
opcode_idx: [0x05]
|
||||
format: [pref_op_imm_16_v_8]
|
||||
prefix: wide
|
||||
properties: [range_1]
|
||||
- sig: deprecated.callthisrange imm:u16, v:in:top
|
||||
acc: out:top
|
||||
opcode_idx: [0x11]
|
||||
format: [pref_op_imm_16_v_8]
|
||||
prefix: deprecated
|
||||
properties: [range_1]
|
||||
- sig: supercallthisrange imm1:u8, imm2:u8, v:in:top
|
||||
acc: out:top
|
||||
opcode_idx: [0x32]
|
||||
format: [op_imm1_8_imm2_8_v_8]
|
||||
properties: [jit_ic_slot, two_slot, eight_bit_ic]
|
||||
properties: [jit_ic_slot, two_slot, eight_bit_ic, range_0]
|
||||
- sig: wide.supercallthisrange imm:u16, v:in:top
|
||||
acc: out:top
|
||||
opcode_idx: [0x06]
|
||||
format: [pref_op_imm_16_v_8]
|
||||
prefix: wide
|
||||
properties: [range_0]
|
||||
- sig: supercallarrowrange imm1:u8, imm2:u8, v:in:top
|
||||
acc: inout:top
|
||||
opcode_idx: [0xbb]
|
||||
format: [op_imm1_8_imm2_8_v_8]
|
||||
properties: [jit_ic_slot, two_slot, eight_bit_ic]
|
||||
properties: [jit_ic_slot, two_slot, eight_bit_ic, range_0]
|
||||
- sig: wide.supercallarrowrange imm:u16, v:in:top
|
||||
acc: inout:top
|
||||
opcode_idx: [0x07]
|
||||
format: [pref_op_imm_16_v_8]
|
||||
prefix: wide
|
||||
properties: [range_0]
|
||||
|
||||
- title: definition instuctions
|
||||
description: instructions which define object
|
||||
|
20
isa/isapi.rb
20
isa/isapi.rb
@ -264,6 +264,26 @@ class Instruction < SimpleDelegator
|
||||
dig(:namespace) || 'core'
|
||||
end
|
||||
|
||||
def is_range_0?
|
||||
properties.include?('range_0')
|
||||
end
|
||||
|
||||
def is_range_1?
|
||||
properties.include?('range_1')
|
||||
end
|
||||
|
||||
def is_range_instruction?
|
||||
is_range_0? || is_range_1?
|
||||
end
|
||||
|
||||
def is_return_instruction?
|
||||
properties.include?('return')
|
||||
end
|
||||
|
||||
def is_unconditional_throw_instruction?
|
||||
dig(:prefix) == 'throw' && !properties.include?('conditional_throw')
|
||||
end
|
||||
|
||||
include FreezeMixin
|
||||
freeze_defined_methods
|
||||
end
|
||||
|
@ -260,6 +260,8 @@ public:
|
||||
// Read imm as actually signed / unsigned and cast it to int64 before return
|
||||
auto GetImmData(size_t idx = 0) const;
|
||||
|
||||
auto GetImmCount() const;
|
||||
|
||||
/**
|
||||
* Primary and Secondary Opcodes are used in interpreter/verifier instruction dispatch
|
||||
* while full Opcode is typically used for various instruction property query.
|
||||
@ -405,7 +407,25 @@ public:
|
||||
return Size(GetFormat(opcode));
|
||||
}
|
||||
|
||||
static std::optional<uint64_t> SafeAdd(uint64_t a, uint64_t b)
|
||||
{
|
||||
if (a > std::numeric_limits<uint64_t>::max() - b) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return a + b;
|
||||
}
|
||||
|
||||
size_t GetLiteralIndex() const;
|
||||
|
||||
bool IsJumpInstruction() const;
|
||||
|
||||
bool IsReturnOrThrowInstruction() const;
|
||||
|
||||
bool IsRangeInstruction() const;
|
||||
|
||||
std::optional<uint64_t> GetRangeInsLastRegIdx() const;
|
||||
|
||||
std::optional<uint64_t> GetLastVReg() const;
|
||||
};
|
||||
|
||||
template <const BytecodeInstMode Mode>
|
||||
|
@ -269,6 +269,34 @@ inline auto BytecodeInst<Mode>::GetImm() const { // NOLINTNEXTLINE(readability-
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template <const BytecodeInstMode Mode>
|
||||
inline auto BytecodeInst<Mode>::GetImmCount() const {
|
||||
Format format = GetFormat();
|
||||
auto idx = 0;
|
||||
ASSERT_PRINT(HasImm(format, idx), "Instruction has no imm operand");
|
||||
|
||||
if (!HasImm(format, idx)) {
|
||||
return static_cast<size_t>(0);
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt|
|
||||
% fmt = i.format
|
||||
% n = i.operands.count(&:imm?)
|
||||
% next if n == 0
|
||||
|
||||
case Format::<%= fmt.pretty.upcase %>: {
|
||||
return static_cast<size_t>(<%= n %>);
|
||||
}
|
||||
% end
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<const BytecodeInstMode Mode>
|
||||
inline auto BytecodeInst<Mode>::GetImm64(size_t idx /* = 0 */) const {
|
||||
Format format = GetFormat();
|
||||
@ -567,4 +595,108 @@ template<const BytecodeInstMode Mode> inline size_t BytecodeInst<Mode>::GetLiter
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<const BytecodeInstMode Mode>
|
||||
inline bool BytecodeInst<Mode>::IsJumpInstruction() const {
|
||||
switch(GetOpcode()) {
|
||||
% Panda::instructions.each do |i|
|
||||
% if i.jump?
|
||||
case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>:
|
||||
return true;
|
||||
% end
|
||||
% end
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<const BytecodeInstMode Mode>
|
||||
inline bool BytecodeInst<Mode>::IsRangeInstruction() const {
|
||||
switch (GetOpcode()) {
|
||||
% Panda::instructions.each do |i|
|
||||
% if i.is_range_instruction?
|
||||
case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>:
|
||||
return true;
|
||||
% end
|
||||
% end
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template <const BytecodeInstMode Mode>
|
||||
inline std::optional<uint64_t> BytecodeInst<Mode>::GetLastVReg() const {
|
||||
Format format = GetFormat();
|
||||
ASSERT_PRINT(HasVReg(format, 0), "Instruction doesn't have VReg operand with such index");
|
||||
|
||||
if (!HasVReg(format, 0)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt|
|
||||
% fmt = i.format
|
||||
% n = i.operands.count(&:reg?)
|
||||
% next if n == 0
|
||||
%
|
||||
case Format::<%= fmt.pretty.upcase %>: {
|
||||
return GetVReg<BytecodeInstruction::Format::<%=fmt.pretty.upcase%>, <%=n-1%>>();
|
||||
}
|
||||
% end
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template <const BytecodeInstMode Mode>
|
||||
inline std::optional<uint64_t> BytecodeInst<Mode>::GetRangeInsLastRegIdx() const {
|
||||
// For the range instruction, where A stores the number of registers
|
||||
// The actual register index needs to handle 2 cases: B~B+A-1 / B~B+A
|
||||
// range_0 is B~B+A-1
|
||||
// range_1 is B~B+A
|
||||
size_t count = GetImmCount();
|
||||
if (count == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
int64_t range_reg_num = GetImmData(count - 1);
|
||||
switch (GetOpcode()) {
|
||||
% Panda::instructions.each do |i|
|
||||
% if i.is_range_0?
|
||||
case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>:
|
||||
if (range_reg_num > 0) {
|
||||
return SafeAdd(GetLastVReg().value(), range_reg_num - 1);
|
||||
}
|
||||
return GetLastVReg();
|
||||
% end
|
||||
% if i.is_range_1?
|
||||
case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>:
|
||||
return SafeAdd(GetLastVReg().value(), range_reg_num);
|
||||
% end
|
||||
% end
|
||||
default:
|
||||
return std::nullopt;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<const BytecodeInstMode Mode>
|
||||
inline bool BytecodeInst<Mode>::IsReturnOrThrowInstruction() const {
|
||||
switch (GetOpcode()) {
|
||||
% Panda::instructions.each do |i|
|
||||
% if i.is_return_instruction? || i.is_unconditional_throw_instruction?
|
||||
case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>:
|
||||
return true;
|
||||
% end
|
||||
% end
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
@ -20,6 +20,8 @@ host_unittest_action("LibPandaFileTest") {
|
||||
sources = [
|
||||
"bytecode_emitter_tests.cpp",
|
||||
"bytecode_imm_fetch_tests.cpp",
|
||||
"bytecode_jump_range_tests.cpp",
|
||||
"bytecode_rerturn_throw_tests.cpp",
|
||||
"data_protect_test.cpp",
|
||||
"debug_info_extractor_test.cpp",
|
||||
"file_format_version_test.cpp",
|
||||
|
@ -33,6 +33,8 @@ TEST(BytecodeInstruction, Signed)
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM8_V8_V8_V8, 0>()), static_cast<int8_t>(0x17));
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM8_V8_V8_V8, 0, true>()),
|
||||
static_cast<int8_t>(0x17));
|
||||
EXPECT_EQ(inst.GetImmData(0), static_cast<int64_t>(0x17));
|
||||
EXPECT_EQ(inst.GetImmCount(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
@ -42,6 +44,8 @@ TEST(BytecodeInstruction, Signed)
|
||||
EXPECT_EQ(static_cast<uint8_t>(inst.GetOpcode()), 0x4d);
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM8, 0>()), static_cast<int8_t>(-22));
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM8, 0, true>()), static_cast<int8_t>(-22));
|
||||
EXPECT_EQ(inst.GetImmData(0), static_cast<int64_t>(-22));
|
||||
EXPECT_EQ(inst.GetImmCount(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
@ -52,6 +56,8 @@ TEST(BytecodeInstruction, Signed)
|
||||
EXPECT_EQ(inst.GetFormat(), BytecodeInstruction::Format::IMM32);
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM32, 0>()), static_cast<int32_t>(0x1e));
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM32, 0, true>()), static_cast<int32_t>(0x1e));
|
||||
EXPECT_EQ(inst.GetImmData(0), static_cast<int64_t>(0x1e));
|
||||
EXPECT_EQ(inst.GetImmCount(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
@ -60,6 +66,8 @@ TEST(BytecodeInstruction, Signed)
|
||||
BytecodeInstruction inst(bytecode);
|
||||
EXPECT_EQ(static_cast<uint8_t>(inst.GetOpcode()), 0x63);
|
||||
EXPECT_EQ((bit_cast<double>(inst.GetImm<BytecodeInstruction::Format::IMM64, 0, true>())), 3.14);
|
||||
EXPECT_EQ(inst.GetImmData(0), static_cast<int64_t>(0x40091eb851eb851f));
|
||||
EXPECT_EQ(inst.GetImmCount(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,6 +82,8 @@ TEST(BytecodeInstruction, UnsignedOneImm)
|
||||
EXPECT_NE((inst.GetImm<BytecodeInstruction::Format::IMM8_V8_V8_V8, 0>()), static_cast<uint8_t>(0x8e));
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM8_V8_V8_V8, 0, false>()),
|
||||
static_cast<uint8_t>(0x8e));
|
||||
EXPECT_EQ(inst.GetImmData(0), static_cast<int64_t>(0x8e));
|
||||
EXPECT_EQ(inst.GetImmCount(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
@ -84,6 +94,8 @@ TEST(BytecodeInstruction, UnsignedOneImm)
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM8, 0>()), static_cast<int8_t>(0x0d));
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM8, 0, false>()),
|
||||
static_cast<uint8_t>(0x0d));
|
||||
EXPECT_EQ(inst.GetImmData(0), static_cast<int64_t>(0x0d));
|
||||
EXPECT_EQ(inst.GetImmCount(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
@ -94,6 +106,8 @@ TEST(BytecodeInstruction, UnsignedOneImm)
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM16_ID16, 0>()), static_cast<int16_t>(0x80));
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM16_ID16, 0, false>()),
|
||||
static_cast<uint16_t>(0x80));
|
||||
EXPECT_EQ(inst.GetImmData(0), static_cast<int64_t>(0x80));
|
||||
EXPECT_EQ(inst.GetImmCount(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,6 +123,9 @@ TEST(BytecodeInstruction, UnsignedTwoImm)
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM4_IMM4, 1>()), 2);
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM4_IMM4, 0, false>()), 0);
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM4_IMM4, 1, false>()), 2);
|
||||
EXPECT_EQ(inst.GetImmData(0), static_cast<int64_t>(0));
|
||||
EXPECT_EQ(inst.GetImmData(1), static_cast<int64_t>(2));
|
||||
EXPECT_EQ(inst.GetImmCount(), 2);
|
||||
}
|
||||
|
||||
{
|
||||
@ -121,6 +138,9 @@ TEST(BytecodeInstruction, UnsignedTwoImm)
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM8_ID16_IMM8, 1>()), static_cast<int8_t>(1));
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM8_ID16_IMM8, 0, false>()), static_cast<int8_t>(2));
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM8_ID16_IMM8, 1, false>()), static_cast<int8_t>(1));
|
||||
EXPECT_EQ(inst.GetImmData(0), static_cast<int64_t>(2));
|
||||
EXPECT_EQ(inst.GetImmData(1), static_cast<int64_t>(1));
|
||||
EXPECT_EQ(inst.GetImmCount(), 2);
|
||||
}
|
||||
|
||||
{
|
||||
@ -135,6 +155,9 @@ TEST(BytecodeInstruction, UnsignedTwoImm)
|
||||
static_cast<uint8_t>(2));
|
||||
EXPECT_EQ((inst.GetImm<BytecodeInstruction::Format::IMM8_ID16_ID16_IMM16_V8, 1, false>()),
|
||||
static_cast<uint16_t>(2));
|
||||
EXPECT_EQ(inst.GetImmData(0), static_cast<int64_t>(2));
|
||||
EXPECT_EQ(inst.GetImmData(1), static_cast<int64_t>(2));
|
||||
EXPECT_EQ(inst.GetImmCount(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,4 +232,13 @@ TEST(BytecodeInstruction, GetLiteralIndex)
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BytecodeInstruction, GetLastVReg)
|
||||
{
|
||||
{
|
||||
// newobjrange 0xb, 0x3, v6
|
||||
const uint8_t bytecode[] = {0x08, 0x0b, 0x03, 0x06};
|
||||
BytecodeInstruction inst(bytecode);
|
||||
EXPECT_EQ(inst.GetLastVReg().value(), 6);
|
||||
}
|
||||
}
|
||||
} // namespace panda::test
|
||||
|
72
libpandafile/tests/bytecode_jump_range_tests.cpp
Normal file
72
libpandafile/tests/bytecode_jump_range_tests.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <gtest/gtest.h>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
#include "bytecode_instruction-inl.h"
|
||||
|
||||
namespace panda::test {
|
||||
|
||||
TEST(BytecodeInstruction, IsJumpInstruction)
|
||||
{
|
||||
{
|
||||
// jmp -22
|
||||
const uint8_t bytecode[] = {0x4d, 0xea};
|
||||
BytecodeInstruction inst(bytecode);
|
||||
EXPECT_EQ(inst.IsJumpInstruction(), true);
|
||||
}
|
||||
{
|
||||
// a non-jump instruction
|
||||
const uint8_t bytecode[] = {0x08, 0x0b, 0x03, 0x06};
|
||||
BytecodeInstruction inst(bytecode);
|
||||
EXPECT_EQ(inst.IsJumpInstruction(), false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BytecodeInstruction, IsRangeInstruction)
|
||||
{
|
||||
{
|
||||
// newobjrange 0xb, 0x3, v6
|
||||
const uint8_t bytecode[] = {0x08, 0x0b, 0x03, 0x06};
|
||||
BytecodeInstruction inst(bytecode);
|
||||
EXPECT_EQ(inst.IsRangeInstruction(), true);
|
||||
}
|
||||
{
|
||||
// a non-range instruction
|
||||
const uint8_t bytecode[] = {0x44, 0x58};
|
||||
BytecodeInstruction inst(bytecode);
|
||||
EXPECT_EQ(inst.IsRangeInstruction(), false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BytecodeInstruction, GetRangeInsLastRegIdx) {
|
||||
{
|
||||
// a non-range instruction
|
||||
const uint8_t bytecode[] = {0x3f, 0x0a, 0x00, 0x00};
|
||||
BytecodeInstruction inst(bytecode);
|
||||
EXPECT_EQ(inst.GetRangeInsLastRegIdx(), std::nullopt);
|
||||
}
|
||||
{
|
||||
// newobjrange 0xb, 0x3, v6
|
||||
const uint8_t bytecode[] = {0x08, 0x0b, 0x03, 0x06};
|
||||
BytecodeInstruction inst(bytecode);
|
||||
EXPECT_EQ(inst.GetRangeInsLastRegIdx().value(), 8);
|
||||
}
|
||||
}
|
||||
}
|
47
libpandafile/tests/bytecode_rerturn_throw_tests.cpp
Normal file
47
libpandafile/tests/bytecode_rerturn_throw_tests.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <gtest/gtest.h>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
#include "bytecode_instruction-inl.h"
|
||||
|
||||
namespace panda::test {
|
||||
|
||||
TEST(BytecodeInstruction, IsReturnOrThrowInstruction)
|
||||
{
|
||||
{
|
||||
// return
|
||||
const uint8_t bytecode[] = {0x65};
|
||||
BytecodeInstruction inst(bytecode);
|
||||
EXPECT_EQ(inst.IsReturnOrThrowInstruction(), true);
|
||||
}
|
||||
{
|
||||
// throw
|
||||
const uint8_t bytecode[] = {0xfe};
|
||||
BytecodeInstruction inst(bytecode);
|
||||
EXPECT_EQ(inst.IsReturnOrThrowInstruction(), true);
|
||||
}
|
||||
{
|
||||
// not return, not throw
|
||||
const uint8_t bytecode[] = {0x3f, 0x00, 0x0c, 0x00};
|
||||
BytecodeInstruction inst(bytecode);
|
||||
EXPECT_EQ(inst.IsReturnOrThrowInstruction(), false);
|
||||
}
|
||||
}
|
||||
}
|
@ -241,12 +241,7 @@ bool Verifier::CollectIdInInstructions(const panda_file::File::EntityId &method_
|
||||
if (bc_ins.HasFlag(BytecodeInstruction::Flags::LITERALARRAY_ID)) {
|
||||
// the idx of any instruction with a literal id is 0
|
||||
// except defineclasswithbuffer/callruntime.definesendableclass
|
||||
size_t idx = 0;
|
||||
if (bc_ins.GetOpcode() == Opcode::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8 ||
|
||||
bc_ins.GetOpcode() == Opcode::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8 ||
|
||||
bc_ins.GetOpcode() == Opcode::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8) {
|
||||
idx = 1;
|
||||
}
|
||||
size_t idx = bc_ins.GetLiteralIndex();
|
||||
const auto arg_literal_idx = bc_ins.GetId(idx).AsIndex();
|
||||
const auto literal_id = file_->ResolveMethodIndex(method_id, arg_literal_idx);
|
||||
ins_literal_ids_.insert(literal_id.GetOffset());
|
||||
@ -316,48 +311,17 @@ size_t Verifier::GetVRegCount(const BytecodeInstruction &bc_ins)
|
||||
return idx;
|
||||
}
|
||||
|
||||
bool Verifier::IsRangeInstruction(const Opcode &ins_opcode)
|
||||
{
|
||||
switch (ins_opcode) {
|
||||
case Opcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8:
|
||||
case Opcode::WIDE_CALLRANGE_PREF_IMM16_V8:
|
||||
case Opcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
|
||||
case Opcode::WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8:
|
||||
case Opcode::CREATEOBJECTWITHEXCLUDEDKEYS_IMM8_V8_V8:
|
||||
case Opcode::WIDE_CREATEOBJECTWITHEXCLUDEDKEYS_PREF_IMM16_V8_V8:
|
||||
case Opcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8:
|
||||
case Opcode::NEWOBJRANGE_IMM8_IMM8_V8:
|
||||
case Opcode::NEWOBJRANGE_IMM16_IMM8_V8:
|
||||
case Opcode::CALLTHISRANGE_IMM8_IMM8_V8:
|
||||
case Opcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
|
||||
case Opcode::CALLRANGE_IMM8_IMM8_V8:
|
||||
case Opcode::SUPERCALLARROWRANGE_IMM8_IMM8_V8: {
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Verifier::IsRangeInstAndHasInvalidRegIdx(const BytecodeInstruction &bc_ins,
|
||||
const size_t count, uint64_t valid_regs_num)
|
||||
{
|
||||
Opcode ins_opcode = bc_ins.GetOpcode();
|
||||
ASSERT(IsRangeInstruction(ins_opcode));
|
||||
ASSERT(bc_ins.IsRangeInstruction());
|
||||
|
||||
uint64_t reg_idx = bc_ins.GetVReg(FIRST_INDEX);
|
||||
if (IsRegIdxOutOfBounds(reg_idx, valid_regs_num)) { // for [format: +AA/+AAAA vBB vCC], vBB can be verified here
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<uint64_t> range_reg_num = GetRangeRegNum(bc_ins, ins_opcode);
|
||||
if (!range_reg_num.has_value()) {
|
||||
LOG(ERROR, VERIFIER) << "Failed to get range register number!";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<uint64_t> max_ins_reg_idx_opt = CalculateMaxRegIdx(bc_ins, ins_opcode, range_reg_num.value());
|
||||
std::optional<uint64_t> max_ins_reg_idx_opt = bc_ins.GetRangeInsLastRegIdx();
|
||||
if (!max_ins_reg_idx_opt.has_value()) {
|
||||
LOG(ERROR, VERIFIER) << "Integer overflow detected during register index calculation!";
|
||||
return true;
|
||||
@ -371,36 +335,6 @@ bool Verifier::IsRangeInstAndHasInvalidRegIdx(const BytecodeInstruction &bc_ins,
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<uint64_t> Verifier::GetRangeRegNum(const BytecodeInstruction &bc_ins, Opcode ins_opcode)
|
||||
{
|
||||
// For the range instruction, where A stores the number of registers
|
||||
// The actual register indexes are divided into three categories: 0~B+A-1 / 0~B+A / 0~C+A
|
||||
switch (ins_opcode) {
|
||||
// format: +AA vBB -> max register idx: B+A-1
|
||||
case Opcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8:
|
||||
case Opcode::WIDE_CALLRANGE_PREF_IMM16_V8:
|
||||
case Opcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
|
||||
case Opcode::WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8:
|
||||
// format: +AA/+AAAA vBB vCC -> max register idx: C+A
|
||||
case Opcode::CREATEOBJECTWITHEXCLUDEDKEYS_IMM8_V8_V8:
|
||||
case Opcode::WIDE_CREATEOBJECTWITHEXCLUDEDKEYS_PREF_IMM16_V8_V8:
|
||||
// format: +AAAA vBB -> max register idx: B+A
|
||||
case Opcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8:
|
||||
return bc_ins.GetImmData(FIRST_INDEX);
|
||||
// format: ic +AA vBB -> max register idx: B+A-1
|
||||
case Opcode::NEWOBJRANGE_IMM8_IMM8_V8:
|
||||
case Opcode::NEWOBJRANGE_IMM16_IMM8_V8:
|
||||
case Opcode::CALLTHISRANGE_IMM8_IMM8_V8:
|
||||
case Opcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
|
||||
case Opcode::CALLRANGE_IMM8_IMM8_V8:
|
||||
case Opcode::SUPERCALLARROWRANGE_IMM8_IMM8_V8:
|
||||
return bc_ins.GetImmData(SECOND_INDEX);
|
||||
default:
|
||||
LOG(ERROR, VERIFIER) << "Instruction processing error: There is an unprocessed range instruction!";
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
bool Verifier::IsRegIdxOutOfBounds(uint64_t reg_idx, uint64_t valid_regs_num)
|
||||
{
|
||||
if (reg_idx >= valid_regs_num) {
|
||||
@ -411,46 +345,9 @@ bool Verifier::IsRegIdxOutOfBounds(uint64_t reg_idx, uint64_t valid_regs_num)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<uint64_t> Verifier::CalculateMaxRegIdx(const BytecodeInstruction &bc_ins,
|
||||
Opcode ins_opcode, uint64_t range_reg_num)
|
||||
{
|
||||
switch (ins_opcode) {
|
||||
// format: +AA vBB -> max register idx: B+A-1
|
||||
case Opcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8:
|
||||
case Opcode::WIDE_CALLRANGE_PREF_IMM16_V8:
|
||||
case Opcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
|
||||
case Opcode::WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8:
|
||||
if (range_reg_num > 0) {
|
||||
return SafeAdd(bc_ins.GetVReg(FIRST_INDEX), range_reg_num - 1);
|
||||
}
|
||||
return SafeAdd(bc_ins.GetVReg(FIRST_INDEX), range_reg_num);
|
||||
// format: +AAAA vBB -> max register idx: B+A
|
||||
case Opcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8:
|
||||
return SafeAdd(bc_ins.GetVReg(FIRST_INDEX), range_reg_num);
|
||||
// format: ic +AA vBB -> max register idx: B+A-1
|
||||
case Opcode::NEWOBJRANGE_IMM8_IMM8_V8:
|
||||
case Opcode::NEWOBJRANGE_IMM16_IMM8_V8:
|
||||
case Opcode::CALLTHISRANGE_IMM8_IMM8_V8:
|
||||
case Opcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
|
||||
case Opcode::CALLRANGE_IMM8_IMM8_V8:
|
||||
case Opcode::SUPERCALLARROWRANGE_IMM8_IMM8_V8:
|
||||
if (range_reg_num > 0) {
|
||||
return SafeAdd(bc_ins.GetVReg(FIRST_INDEX), range_reg_num - 1);
|
||||
}
|
||||
return SafeAdd(bc_ins.GetVReg(FIRST_INDEX), range_reg_num);
|
||||
// format: +AA/+AAAA vBB vCC -> max register idx: C+A
|
||||
case Opcode::CREATEOBJECTWITHEXCLUDEDKEYS_IMM8_V8_V8:
|
||||
case Opcode::WIDE_CREATEOBJECTWITHEXCLUDEDKEYS_PREF_IMM16_V8_V8:
|
||||
return SafeAdd(bc_ins.GetVReg(SECOND_INDEX), range_reg_num);
|
||||
default:
|
||||
LOG(ERROR, VERIFIER) << "Instruction processing error: Unprocessed range instruction!";
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
bool Verifier::CheckVRegIdx(const BytecodeInstruction &bc_ins, const size_t count, uint64_t valid_regs_num)
|
||||
{
|
||||
if (IsRangeInstruction(bc_ins.GetOpcode()) &&
|
||||
if (bc_ins.IsRangeInstruction() &&
|
||||
IsRangeInstAndHasInvalidRegIdx(bc_ins, count, valid_regs_num)) {
|
||||
return false;
|
||||
}
|
||||
@ -669,77 +566,6 @@ bool Verifier::VerifyLiteralArrays()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Verifier::IsJumpInstruction(const Opcode &ins_opcode)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
switch (ins_opcode) {
|
||||
case Opcode::JMP_IMM8:
|
||||
case Opcode::JMP_IMM16:
|
||||
case Opcode::JEQZ_IMM8:
|
||||
case Opcode::JEQZ_IMM16:
|
||||
case Opcode::JNEZ_IMM8:
|
||||
case Opcode::JSTRICTEQZ_IMM8:
|
||||
case Opcode::JNSTRICTEQZ_IMM8:
|
||||
case Opcode::JEQNULL_IMM8:
|
||||
case Opcode::JNENULL_IMM8:
|
||||
case Opcode::JSTRICTEQNULL_IMM8:
|
||||
case Opcode::JNSTRICTEQNULL_IMM8:
|
||||
case Opcode::JEQUNDEFINED_IMM8:
|
||||
case Opcode::JNEUNDEFINED_IMM8:
|
||||
case Opcode::JSTRICTEQUNDEFINED_IMM8:
|
||||
case Opcode::JNSTRICTEQUNDEFINED_IMM8:
|
||||
case Opcode::JEQ_V8_IMM8:
|
||||
case Opcode::JNE_V8_IMM8:
|
||||
case Opcode::JSTRICTEQ_V8_IMM8:
|
||||
case Opcode::JNSTRICTEQ_V8_IMM8:
|
||||
case Opcode::JMP_IMM32:
|
||||
case Opcode::JEQZ_IMM32:
|
||||
case Opcode::JNEZ_IMM16:
|
||||
case Opcode::JNEZ_IMM32:
|
||||
case Opcode::JSTRICTEQZ_IMM16:
|
||||
case Opcode::JNSTRICTEQZ_IMM16:
|
||||
case Opcode::JEQNULL_IMM16:
|
||||
case Opcode::JNENULL_IMM16:
|
||||
case Opcode::JSTRICTEQNULL_IMM16:
|
||||
case Opcode::JNSTRICTEQNULL_IMM16:
|
||||
case Opcode::JEQUNDEFINED_IMM16:
|
||||
case Opcode::JNEUNDEFINED_IMM16:
|
||||
case Opcode::JSTRICTEQUNDEFINED_IMM16:
|
||||
case Opcode::JEQ_V8_IMM16:
|
||||
case Opcode::JNE_V8_IMM16:
|
||||
case Opcode::JSTRICTEQ_V8_IMM16:
|
||||
case Opcode::JNSTRICTEQ_V8_IMM16: {
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool Verifier::IsReturnAndThrowInstruction(const Opcode &ins_opcode)
|
||||
{
|
||||
switch (ins_opcode) {
|
||||
case Opcode::RETURN:
|
||||
case Opcode::RETURNUNDEFINED:
|
||||
case Opcode::THROW_PREF_NONE:
|
||||
case Opcode::THROW_NOTEXISTS_PREF_NONE:
|
||||
case Opcode::THROW_PATTERNNONCOERCIBLE_PREF_NONE:
|
||||
case Opcode::THROW_DELETESUPERPROPERTY_PREF_NONE:
|
||||
case Opcode::THROW_CONSTASSIGNMENT_PREF_V8: {
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Verifier::PrecomputeInstructionIndices(const BytecodeInstruction &bc_ins_start,
|
||||
const BytecodeInstruction &bc_ins_last)
|
||||
{
|
||||
@ -778,8 +604,7 @@ bool Verifier::VerifyJumpInstruction(const BytecodeInstruction &bc_ins, const By
|
||||
// update maximum backward offset
|
||||
const auto bc_ins_backward_size = bc_ins.GetAddress() - bc_ins_first.GetAddress();
|
||||
|
||||
Opcode ins_opcode = bc_ins.GetOpcode();
|
||||
if (IsJumpInstruction(ins_opcode)) {
|
||||
if (bc_ins.IsJumpInstruction()) {
|
||||
std::optional<int64_t> immdata = GetFirstImmFromInstruction(bc_ins);
|
||||
if (!immdata.has_value()) {
|
||||
LOG(ERROR, VERIFIER) << "Fail to get immediate data!";
|
||||
@ -971,49 +796,55 @@ bool Verifier::VerifyMethodRegisterIndex(panda_file::CodeDataAccessor &code_acce
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Verifier::VerifyMethodInstructions(const VerifyMethodParams ¶ms)
|
||||
bool Verifier::VerifyMethodInstructions(const MethodInfos &infos)
|
||||
{
|
||||
while (params.bc_ins.GetAddress() != params.bc_ins_last.GetAddress()) {
|
||||
if (params.bc_ins.GetAddress() > params.bc_ins_last.GetAddress()) {
|
||||
LOG(ERROR, VERIFIER) << "> error encountered at " << params.method_accessor.GetCodeId().value()
|
||||
<< " (0x" << std::hex << params.method_accessor.GetCodeId().value()
|
||||
auto current_ins = infos.bc_ins;
|
||||
auto last_ins = infos.bc_ins_last;
|
||||
auto code_id = infos.method_accessor.GetCodeId().value();
|
||||
auto method_id = infos.method_id;
|
||||
auto valid_regs_num = infos.valid_regs_num.value();
|
||||
auto ins_slot_num = infos.ins_slot_num;
|
||||
auto has_slot = infos.has_slot;
|
||||
auto is_two_slot = infos.is_two_slot;
|
||||
|
||||
while (current_ins.GetAddress() != last_ins.GetAddress()) {
|
||||
if (current_ins.GetAddress() > last_ins.GetAddress()) {
|
||||
LOG(ERROR, VERIFIER) << "> error encountered at " << code_id
|
||||
<< " (0x" << std::hex << code_id
|
||||
<< "). bytecode instructions sequence corrupted for method "
|
||||
<< params.method_id
|
||||
<< method_id
|
||||
<< "! went out of bounds";
|
||||
return false;
|
||||
}
|
||||
Opcode ins_opcode = params.bc_ins.GetOpcode();
|
||||
if (!IsJumpInstruction(ins_opcode) && !IsReturnAndThrowInstruction(ins_opcode)
|
||||
&& params.bc_ins.GetNext().GetAddress() == params.bc_ins_last.GetAddress()) {
|
||||
LOG(ERROR, VERIFIER) << "> error encountered at " << params.method_accessor.GetCodeId().value()
|
||||
<< " (0x" << std::hex << params.method_accessor.GetCodeId().value()
|
||||
if (!current_ins.IsJumpInstruction() && !current_ins.IsReturnOrThrowInstruction()
|
||||
&& current_ins.GetNext().GetAddress() == last_ins.GetAddress()) {
|
||||
LOG(ERROR, VERIFIER) << "> error encountered at " << code_id
|
||||
<< " (0x" << std::hex << code_id
|
||||
<< "). bytecode instructions sequence corrupted for method "
|
||||
<< params.method_id
|
||||
<< method_id
|
||||
<< "! went out of bounds";
|
||||
return false;
|
||||
}
|
||||
const size_t count = GetVRegCount(params.bc_ins);
|
||||
if (count != 0 && !CheckVRegIdx(params.bc_ins, count, params.valid_regs_num.value())) {
|
||||
const size_t count = GetVRegCount(current_ins);
|
||||
if (count != 0 && !CheckVRegIdx(current_ins, count, valid_regs_num)) {
|
||||
return false;
|
||||
}
|
||||
if (!VerifyJumpInstruction(params.bc_ins, params.bc_ins_last,
|
||||
params.bc_ins_init, params.ins_arr,
|
||||
params.method_accessor.GetCodeId().value())) {
|
||||
if (!VerifyJumpInstruction(current_ins, last_ins,
|
||||
infos.bc_ins_init, infos.ins_arr,
|
||||
code_id)) {
|
||||
LOG(ERROR, VERIFIER) << "Invalid target position of jump instruction";
|
||||
return false;
|
||||
}
|
||||
if (!GetIcSlotFromInstruction(params.bc_ins, params.ins_slot_num,
|
||||
params.has_slot, params.is_two_slot)) {
|
||||
if (!GetIcSlotFromInstruction(current_ins, ins_slot_num,
|
||||
has_slot, is_two_slot)) {
|
||||
LOG(ERROR, VERIFIER) << "Fail to get first slot index!";
|
||||
return false;
|
||||
}
|
||||
params.bc_ins = params.bc_ins.GetNext();
|
||||
current_ins = current_ins.GetNext();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Verifier::CheckConstantPoolMethodContent(const panda_file::File::EntityId &method_id)
|
||||
{
|
||||
panda_file::MethodDataAccessor method_accessor(*file_, method_id);
|
||||
@ -1031,8 +862,8 @@ bool Verifier::CheckConstantPoolMethodContent(const panda_file::File::EntityId &
|
||||
bool has_slot = false;
|
||||
bool is_two_slot = false;
|
||||
std::optional<uint64_t> valid_regs_num = 0;
|
||||
VerifyMethodParams params = {bc_ins_init, bc_ins, bc_ins_last, method_accessor, method_id,
|
||||
valid_regs_num, ins_arr, ins_slot_num, has_slot, is_two_slot};
|
||||
MethodInfos infos = {bc_ins_init, bc_ins, bc_ins_last, method_accessor, method_id,
|
||||
valid_regs_num, ins_arr, ins_slot_num, has_slot, is_two_slot};
|
||||
if (ins_size <= 0) {
|
||||
LOG(ERROR, VERIFIER) << "Fail to verify code size!";
|
||||
return false;
|
||||
@ -1052,7 +883,7 @@ bool Verifier::CheckConstantPoolMethodContent(const panda_file::File::EntityId &
|
||||
LOG(ERROR, VERIFIER) << "Fail to verify try blocks or catch blocks!";
|
||||
return false;
|
||||
}
|
||||
if (!VerifyMethodInstructions(params)) {
|
||||
if (!VerifyMethodInstructions(infos)) {
|
||||
LOG(ERROR, VERIFIER) << "Fail to verify method instructions!";
|
||||
return false;
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ enum class ActionType {
|
||||
COLLECTINFOS,
|
||||
};
|
||||
|
||||
struct VerifyMethodParams {
|
||||
struct MethodInfos {
|
||||
const BytecodeInstruction &bc_ins_init;
|
||||
BytecodeInstruction &bc_ins;
|
||||
const BytecodeInstruction &bc_ins_last;
|
||||
@ -92,13 +92,9 @@ private:
|
||||
bool VerifyMethodId(const uint32_t &method_id) const;
|
||||
bool VerifyLiteralId(const uint32_t &literal_id) const;
|
||||
bool VerifyStringId(const uint32_t &string_id) const;
|
||||
bool IsRangeInstruction(const Opcode &ins_opcode);
|
||||
bool IsRangeInstAndHasInvalidRegIdx(const BytecodeInstruction &bc_ins,
|
||||
const size_t count, uint64_t valid_regs_num);
|
||||
std::optional<uint64_t> GetRangeRegNum(const BytecodeInstruction &bc_ins, Opcode ins_opcode);
|
||||
bool IsRegIdxOutOfBounds(uint64_t reg_idx, uint64_t valid_regs_num);
|
||||
std::optional<uint64_t> CalculateMaxRegIdx(const BytecodeInstruction &bc_ins,
|
||||
Opcode ins_opcode, uint64_t range_reg_num);
|
||||
bool CheckVRegIdx(const BytecodeInstruction &bc_ins, const size_t count, uint64_t valid_regs_num);
|
||||
std::optional<int64_t> GetFirstImmFromInstruction(const BytecodeInstruction &bc_ins);
|
||||
std::optional<uint64_t> GetSlotNumberFromAnnotation(panda_file::MethodDataAccessor &method_accessor);
|
||||
@ -108,7 +104,6 @@ private:
|
||||
bool IsModuleLiteralId(const panda_file::File::EntityId &id) const;
|
||||
bool VerifySingleLiteralArray(const panda_file::File::EntityId &literal_id);
|
||||
bool VerifyLiteralArrays();
|
||||
bool IsJumpInstruction(const Opcode &ins_opcode);
|
||||
bool VerifyJumpInstruction(const BytecodeInstruction &bc_ins, const BytecodeInstruction &bc_ins_last,
|
||||
const BytecodeInstruction &bc_ins_init, const uint8_t *ins_arr,
|
||||
panda_file::File::EntityId code_id);
|
||||
@ -123,12 +118,11 @@ private:
|
||||
const BytecodeInstruction &bc_ins_last);
|
||||
bool VerifyTryBlocks(panda_file::CodeDataAccessor &code_accessor, const BytecodeInstruction &bc_ins,
|
||||
const BytecodeInstruction &bc_ins_last);
|
||||
bool IsReturnAndThrowInstruction(const Opcode &ins_opcode);
|
||||
bool PrecomputeInstructionIndices(const BytecodeInstruction &bc_ins_start, const BytecodeInstruction &bc_ins_last);
|
||||
bool IsMethodBytecodeInstruction(const BytecodeInstruction &bc_ins_cur);
|
||||
bool VerifyMethodRegisterIndex(panda_file::CodeDataAccessor &code_accessor,
|
||||
std::optional<uint64_t> &max_reg_idx);
|
||||
bool VerifyMethodInstructions(const VerifyMethodParams ¶ms);
|
||||
bool VerifyMethodInstructions(const MethodInfos &infos);
|
||||
|
||||
inline bool IsImpureNaN(double value)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user