1b1994897Sopenharmony_ci/*
2b1994897Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
3b1994897Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4b1994897Sopenharmony_ci * you may not use this file except in compliance with the License.
5b1994897Sopenharmony_ci * You may obtain a copy of the License at
6b1994897Sopenharmony_ci *
7b1994897Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8b1994897Sopenharmony_ci *
9b1994897Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10b1994897Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11b1994897Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12b1994897Sopenharmony_ci * See the License for the specific language governing permissions and
13b1994897Sopenharmony_ci * limitations under the License.
14b1994897Sopenharmony_ci */
15b1994897Sopenharmony_ci#include <codecvt>
16b1994897Sopenharmony_ci#include <locale>
17b1994897Sopenharmony_ci
18b1994897Sopenharmony_ci#include "verifier.h"
19b1994897Sopenharmony_ci#include "class_data_accessor-inl.h"
20b1994897Sopenharmony_ci#include "libpandafile/util/collect_util.h"
21b1994897Sopenharmony_ci#include "zlib.h"
22b1994897Sopenharmony_ci
23b1994897Sopenharmony_cinamespace panda::verifier {
24b1994897Sopenharmony_ci
25b1994897Sopenharmony_ciVerifier::Verifier(const std::string &filename)
26b1994897Sopenharmony_ci{
27b1994897Sopenharmony_ci    auto file_to_verify = panda_file::File::Open(filename);
28b1994897Sopenharmony_ci    file_.swap(file_to_verify);
29b1994897Sopenharmony_ci}
30b1994897Sopenharmony_ci
31b1994897Sopenharmony_cibool Verifier::Verify()
32b1994897Sopenharmony_ci{
33b1994897Sopenharmony_ci    if (!VerifyChecksum()) {
34b1994897Sopenharmony_ci        return false;
35b1994897Sopenharmony_ci    }
36b1994897Sopenharmony_ci
37b1994897Sopenharmony_ci    if (!CollectIdInfos()) {
38b1994897Sopenharmony_ci        return false;
39b1994897Sopenharmony_ci    }
40b1994897Sopenharmony_ci
41b1994897Sopenharmony_ci    if (!VerifyConstantPool()) {
42b1994897Sopenharmony_ci        return false;
43b1994897Sopenharmony_ci    }
44b1994897Sopenharmony_ci
45b1994897Sopenharmony_ci    return true;
46b1994897Sopenharmony_ci}
47b1994897Sopenharmony_ci
48b1994897Sopenharmony_cibool Verifier::CollectIdInfos()
49b1994897Sopenharmony_ci{
50b1994897Sopenharmony_ci    if (file_ == nullptr) {
51b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Failed to verify empty abc file!";
52b1994897Sopenharmony_ci        return false;
53b1994897Sopenharmony_ci    }
54b1994897Sopenharmony_ci    GetConstantPoolIds();
55b1994897Sopenharmony_ci    if (include_literal_array_ids) {
56b1994897Sopenharmony_ci        GetLiteralIds();
57b1994897Sopenharmony_ci    }
58b1994897Sopenharmony_ci    return CheckConstantPool(verifier::ActionType::COLLECTINFOS);
59b1994897Sopenharmony_ci}
60b1994897Sopenharmony_ci
61b1994897Sopenharmony_cibool Verifier::VerifyChecksum()
62b1994897Sopenharmony_ci{
63b1994897Sopenharmony_ci    if (file_ == nullptr) {
64b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Failed to verify empty abc file!";
65b1994897Sopenharmony_ci        return false;
66b1994897Sopenharmony_ci    }
67b1994897Sopenharmony_ci    uint32_t file_size = file_->GetHeader()->file_size;
68b1994897Sopenharmony_ci    ASSERT(file_size > FILE_CONTENT_OFFSET);
69b1994897Sopenharmony_ci    uint32_t cal_checksum = adler32(1, file_->GetBase() + FILE_CONTENT_OFFSET, file_size - FILE_CONTENT_OFFSET);
70b1994897Sopenharmony_ci    return file_->GetHeader()->checksum == cal_checksum;
71b1994897Sopenharmony_ci}
72b1994897Sopenharmony_ci
73b1994897Sopenharmony_cibool Verifier::VerifyConstantPool()
74b1994897Sopenharmony_ci{
75b1994897Sopenharmony_ci    if (file_ == nullptr) {
76b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Failed to verify empty abc file!";
77b1994897Sopenharmony_ci        return false;
78b1994897Sopenharmony_ci    }
79b1994897Sopenharmony_ci
80b1994897Sopenharmony_ci    if (!CheckConstantPoolIndex()) {
81b1994897Sopenharmony_ci        return false;
82b1994897Sopenharmony_ci    }
83b1994897Sopenharmony_ci
84b1994897Sopenharmony_ci    if (!CheckConstantPool(verifier::ActionType::CHECKCONSTPOOLCONTENT)) {
85b1994897Sopenharmony_ci        return false;
86b1994897Sopenharmony_ci    }
87b1994897Sopenharmony_ci
88b1994897Sopenharmony_ci    if (!VerifyLiteralArrays()) {
89b1994897Sopenharmony_ci        return false;
90b1994897Sopenharmony_ci    }
91b1994897Sopenharmony_ci
92b1994897Sopenharmony_ci    return true;
93b1994897Sopenharmony_ci}
94b1994897Sopenharmony_ci
95b1994897Sopenharmony_cibool Verifier::VerifyRegisterIndex()
96b1994897Sopenharmony_ci{
97b1994897Sopenharmony_ci    if (file_ == nullptr) {
98b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Failed to verify empty abc file!";
99b1994897Sopenharmony_ci        return false;
100b1994897Sopenharmony_ci    }
101b1994897Sopenharmony_ci
102b1994897Sopenharmony_ci    for (const auto id : all_method_ids_) {
103b1994897Sopenharmony_ci        const panda_file::File::EntityId method_id = panda_file::File::EntityId(id);
104b1994897Sopenharmony_ci        panda_file::MethodDataAccessor method_accessor {*file_, method_id};
105b1994897Sopenharmony_ci        if (!method_accessor.GetCodeId().has_value()) {
106b1994897Sopenharmony_ci            continue;
107b1994897Sopenharmony_ci        }
108b1994897Sopenharmony_ci        panda_file::CodeDataAccessor code_data(*file_, method_accessor.GetCodeId().value());
109b1994897Sopenharmony_ci        const uint64_t reg_nums = code_data.GetNumVregs();
110b1994897Sopenharmony_ci        const uint64_t arg_nums = code_data.GetNumArgs();
111b1994897Sopenharmony_ci        const std::optional<uint64_t> valid_regs_num = SafeAdd(reg_nums, arg_nums);
112b1994897Sopenharmony_ci        if (!valid_regs_num.has_value()) {
113b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "Integer overflow detected during register index calculation!";
114b1994897Sopenharmony_ci            return false;
115b1994897Sopenharmony_ci        }
116b1994897Sopenharmony_ci        if (valid_regs_num.value() > MAX_REGISTER_INDEX + 1) {
117b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "Register index exceeds the maximum allowable value (0xffff)!";
118b1994897Sopenharmony_ci            return false;
119b1994897Sopenharmony_ci        }
120b1994897Sopenharmony_ci        auto bc_ins = BytecodeInstruction(code_data.GetInstructions());
121b1994897Sopenharmony_ci        const auto bc_ins_last = bc_ins.JumpTo(code_data.GetCodeSize());
122b1994897Sopenharmony_ci        ASSERT(arg_nums >= DEFAULT_ARGUMENT_NUMBER);
123b1994897Sopenharmony_ci        while (bc_ins.GetAddress() < bc_ins_last.GetAddress()) {
124b1994897Sopenharmony_ci            const size_t count = GetVRegCount(bc_ins);
125b1994897Sopenharmony_ci            if (count == 0) { // Skip instructions that do not use registers
126b1994897Sopenharmony_ci                bc_ins = bc_ins.GetNext();
127b1994897Sopenharmony_ci                continue;
128b1994897Sopenharmony_ci            }
129b1994897Sopenharmony_ci            if (!CheckVRegIdx(bc_ins, count, valid_regs_num.value())) {
130b1994897Sopenharmony_ci                return false;
131b1994897Sopenharmony_ci            }
132b1994897Sopenharmony_ci            bc_ins = bc_ins.GetNext();
133b1994897Sopenharmony_ci        }
134b1994897Sopenharmony_ci    }
135b1994897Sopenharmony_ci    return true;
136b1994897Sopenharmony_ci}
137b1994897Sopenharmony_ci
138b1994897Sopenharmony_cibool Verifier::VerifyConstantPoolIndex()
139b1994897Sopenharmony_ci{
140b1994897Sopenharmony_ci    if (file_ == nullptr) {
141b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Failed to verify empty abc file!";
142b1994897Sopenharmony_ci        return false;
143b1994897Sopenharmony_ci    }
144b1994897Sopenharmony_ci
145b1994897Sopenharmony_ci    if (!CheckConstantPoolIndex()) {
146b1994897Sopenharmony_ci        return false;
147b1994897Sopenharmony_ci    }
148b1994897Sopenharmony_ci
149b1994897Sopenharmony_ci    return true;
150b1994897Sopenharmony_ci}
151b1994897Sopenharmony_ci
152b1994897Sopenharmony_cibool Verifier::VerifyConstantPoolContent()
153b1994897Sopenharmony_ci{
154b1994897Sopenharmony_ci    if (file_ == nullptr) {
155b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Failed to verify empty abc file!";
156b1994897Sopenharmony_ci        return false;
157b1994897Sopenharmony_ci    }
158b1994897Sopenharmony_ci
159b1994897Sopenharmony_ci    if (!CheckConstantPool(verifier::ActionType::CHECKCONSTPOOLCONTENT)) {
160b1994897Sopenharmony_ci        return false;
161b1994897Sopenharmony_ci    }
162b1994897Sopenharmony_ci
163b1994897Sopenharmony_ci    if (!VerifyLiteralArrays()) {
164b1994897Sopenharmony_ci        return false;
165b1994897Sopenharmony_ci    }
166b1994897Sopenharmony_ci
167b1994897Sopenharmony_ci    return true;
168b1994897Sopenharmony_ci}
169b1994897Sopenharmony_ci
170b1994897Sopenharmony_civoid Verifier::GetConstantPoolIds()
171b1994897Sopenharmony_ci{
172b1994897Sopenharmony_ci    if (constant_pool_ids_.size() != 0) {
173b1994897Sopenharmony_ci        return;
174b1994897Sopenharmony_ci    }
175b1994897Sopenharmony_ci    auto index_headers = file_->GetIndexHeaders();
176b1994897Sopenharmony_ci    for (const auto &index_header : index_headers) {
177b1994897Sopenharmony_ci        auto region_indexs = file_->GetMethodIndex(&index_header);
178b1994897Sopenharmony_ci        for (auto &index : region_indexs) {
179b1994897Sopenharmony_ci            constant_pool_ids_.push_back(index.GetOffset());
180b1994897Sopenharmony_ci        }
181b1994897Sopenharmony_ci    }
182b1994897Sopenharmony_ci}
183b1994897Sopenharmony_ci
184b1994897Sopenharmony_civoid Verifier::GetLiteralIds()
185b1994897Sopenharmony_ci{
186b1994897Sopenharmony_ci    if (literal_ids_.size() != 0) {
187b1994897Sopenharmony_ci        return;
188b1994897Sopenharmony_ci    }
189b1994897Sopenharmony_ci
190b1994897Sopenharmony_ci    if (panda_file::ContainsLiteralArrayInHeader(file_->GetHeader()->version)) {
191b1994897Sopenharmony_ci        const auto literal_arrays = file_->GetLiteralArrays();
192b1994897Sopenharmony_ci        PushToLiteralIds(literal_arrays);
193b1994897Sopenharmony_ci    } else {
194b1994897Sopenharmony_ci        panda::libpandafile::CollectUtil collect_util;
195b1994897Sopenharmony_ci        std::unordered_set<uint32_t> literal_array_ids;
196b1994897Sopenharmony_ci        collect_util.CollectLiteralArray(*file_, literal_array_ids);
197b1994897Sopenharmony_ci        PushToLiteralIds(literal_array_ids);
198b1994897Sopenharmony_ci    }
199b1994897Sopenharmony_ci}
200b1994897Sopenharmony_ci
201b1994897Sopenharmony_citemplate <typename T>
202b1994897Sopenharmony_civoid Verifier::PushToLiteralIds(T &ids)
203b1994897Sopenharmony_ci{
204b1994897Sopenharmony_ci    for (const auto id : ids) {
205b1994897Sopenharmony_ci        literal_ids_.push_back(id);
206b1994897Sopenharmony_ci    }
207b1994897Sopenharmony_ci}
208b1994897Sopenharmony_ci
209b1994897Sopenharmony_cibool Verifier::CheckConstantPoolActions(const verifier::ActionType type, panda_file::File::EntityId method_id)
210b1994897Sopenharmony_ci{
211b1994897Sopenharmony_ci    switch (type) {
212b1994897Sopenharmony_ci        case verifier::ActionType::CHECKCONSTPOOLCONTENT: {
213b1994897Sopenharmony_ci            return CheckConstantPoolMethodContent(method_id);
214b1994897Sopenharmony_ci        }
215b1994897Sopenharmony_ci        case verifier::ActionType::COLLECTINFOS: {
216b1994897Sopenharmony_ci            all_method_ids_.push_back(method_id.GetOffset());
217b1994897Sopenharmony_ci            return CollectIdInInstructions(method_id);
218b1994897Sopenharmony_ci        }
219b1994897Sopenharmony_ci        default: {
220b1994897Sopenharmony_ci            return true;
221b1994897Sopenharmony_ci        }
222b1994897Sopenharmony_ci    }
223b1994897Sopenharmony_ci}
224b1994897Sopenharmony_ci
225b1994897Sopenharmony_cibool Verifier::CollectIdInInstructions(const panda_file::File::EntityId &method_id)
226b1994897Sopenharmony_ci{
227b1994897Sopenharmony_ci    panda_file::MethodDataAccessor method_accessor(*file_, method_id);
228b1994897Sopenharmony_ci    ASSERT(method_accessor.GetCodeId().has_value());
229b1994897Sopenharmony_ci    panda_file::CodeDataAccessor code_accessor(*file_, method_accessor.GetCodeId().value());
230b1994897Sopenharmony_ci    const auto ins_size = code_accessor.GetCodeSize();
231b1994897Sopenharmony_ci    const auto ins_arr = code_accessor.GetInstructions();
232b1994897Sopenharmony_ci
233b1994897Sopenharmony_ci    auto bc_ins = BytecodeInstruction(ins_arr);
234b1994897Sopenharmony_ci    const auto bc_ins_last = bc_ins.JumpTo(ins_size);
235b1994897Sopenharmony_ci
236b1994897Sopenharmony_ci    while (bc_ins.GetAddress() < bc_ins_last.GetAddress()) {
237b1994897Sopenharmony_ci        if (!bc_ins.IsPrimaryOpcodeValid()) {
238b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "Fail to verify primary opcode!";
239b1994897Sopenharmony_ci            return false;
240b1994897Sopenharmony_ci        }
241b1994897Sopenharmony_ci        if (bc_ins.HasFlag(BytecodeInstruction::Flags::LITERALARRAY_ID)) {
242b1994897Sopenharmony_ci            // the idx of any instruction with a literal id is 0
243b1994897Sopenharmony_ci            // except defineclasswithbuffer/callruntime.definesendableclass
244b1994897Sopenharmony_ci            size_t idx = bc_ins.GetLiteralIndex();
245b1994897Sopenharmony_ci            const auto arg_literal_idx = bc_ins.GetId(idx).AsIndex();
246b1994897Sopenharmony_ci            const auto literal_id = file_->ResolveMethodIndex(method_id, arg_literal_idx);
247b1994897Sopenharmony_ci            ins_literal_ids_.insert(literal_id.GetOffset());
248b1994897Sopenharmony_ci        }
249b1994897Sopenharmony_ci        if (bc_ins.HasFlag(BytecodeInstruction::Flags::METHOD_ID)) {
250b1994897Sopenharmony_ci            const auto arg_method_idx = bc_ins.GetId().AsIndex();
251b1994897Sopenharmony_ci            const auto arg_method_id = file_->ResolveMethodIndex(method_id, arg_method_idx);
252b1994897Sopenharmony_ci            ins_method_ids_.insert(arg_method_id.GetOffset());
253b1994897Sopenharmony_ci        }
254b1994897Sopenharmony_ci        if (bc_ins.HasFlag(BytecodeInstruction::Flags::STRING_ID)) {
255b1994897Sopenharmony_ci            const auto arg_string_idx = bc_ins.GetId().AsIndex();
256b1994897Sopenharmony_ci            const auto string_id = file_->ResolveOffsetByIndex(method_id, arg_string_idx);
257b1994897Sopenharmony_ci            ins_string_ids_.insert(string_id.GetOffset());
258b1994897Sopenharmony_ci        }
259b1994897Sopenharmony_ci        bc_ins = bc_ins.GetNext();
260b1994897Sopenharmony_ci    }
261b1994897Sopenharmony_ci    return true;
262b1994897Sopenharmony_ci}
263b1994897Sopenharmony_ci
264b1994897Sopenharmony_civoid Verifier::CollectModuleLiteralId(const panda_file::File::EntityId &field_id)
265b1994897Sopenharmony_ci{
266b1994897Sopenharmony_ci    panda_file::FieldDataAccessor field_accessor(*file_, field_id);
267b1994897Sopenharmony_ci    const auto literal_id = field_accessor.GetValue<uint32_t>().value();
268b1994897Sopenharmony_ci    if (std::find(literal_ids_.begin(), literal_ids_.end(), literal_id) != literal_ids_.end()) {
269b1994897Sopenharmony_ci        module_literals_.insert(literal_id);
270b1994897Sopenharmony_ci    }
271b1994897Sopenharmony_ci}
272b1994897Sopenharmony_ci
273b1994897Sopenharmony_cibool Verifier::CheckConstantPool(const verifier::ActionType type)
274b1994897Sopenharmony_ci{
275b1994897Sopenharmony_ci    const auto class_idx = file_->GetClasses();
276b1994897Sopenharmony_ci    for (size_t i = 0; i < class_idx.size(); i++) {
277b1994897Sopenharmony_ci        uint32_t class_id = class_idx[i];
278b1994897Sopenharmony_ci        if (class_id > file_->GetHeader()->file_size) {
279b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "Binary file corrupted. out of bounds (0x" << std::hex
280b1994897Sopenharmony_ci                                 << file_->GetHeader()->file_size;
281b1994897Sopenharmony_ci            return false;
282b1994897Sopenharmony_ci        }
283b1994897Sopenharmony_ci        const panda_file::File::EntityId record_id {class_id};
284b1994897Sopenharmony_ci        if (!file_->IsExternal(record_id)) {
285b1994897Sopenharmony_ci            panda_file::ClassDataAccessor class_accessor {*file_, record_id};
286b1994897Sopenharmony_ci            bool check_res = true;
287b1994897Sopenharmony_ci            class_accessor.EnumerateMethods([&](panda_file::MethodDataAccessor &method_accessor) -> void {
288b1994897Sopenharmony_ci                check_res = check_res && CheckConstantPoolActions(type, method_accessor.GetMethodId());
289b1994897Sopenharmony_ci            });
290b1994897Sopenharmony_ci            if (!check_res) {
291b1994897Sopenharmony_ci                return false;
292b1994897Sopenharmony_ci            }
293b1994897Sopenharmony_ci            if (type == verifier::ActionType::COLLECTINFOS) {
294b1994897Sopenharmony_ci                class_accessor.EnumerateFields([&](panda_file::FieldDataAccessor &field_accessor) -> void {
295b1994897Sopenharmony_ci                    CollectModuleLiteralId(field_accessor.GetFieldId());
296b1994897Sopenharmony_ci                });
297b1994897Sopenharmony_ci            }
298b1994897Sopenharmony_ci        }
299b1994897Sopenharmony_ci    }
300b1994897Sopenharmony_ci
301b1994897Sopenharmony_ci    return true;
302b1994897Sopenharmony_ci}
303b1994897Sopenharmony_ci
304b1994897Sopenharmony_cisize_t Verifier::GetVRegCount(const BytecodeInstruction &bc_ins)
305b1994897Sopenharmony_ci{
306b1994897Sopenharmony_ci    size_t idx = 0; // Represents the idxTH register index in an instruction
307b1994897Sopenharmony_ci    BytecodeInstruction::Format format = bc_ins.GetFormat();
308b1994897Sopenharmony_ci    while (bc_ins.HasVReg(format, idx)) {
309b1994897Sopenharmony_ci        idx++;
310b1994897Sopenharmony_ci    }
311b1994897Sopenharmony_ci    return idx;
312b1994897Sopenharmony_ci}
313b1994897Sopenharmony_ci
314b1994897Sopenharmony_cibool Verifier::IsRangeInstAndHasInvalidRegIdx(const BytecodeInstruction &bc_ins,
315b1994897Sopenharmony_ci                                              const size_t count, uint64_t valid_regs_num)
316b1994897Sopenharmony_ci{
317b1994897Sopenharmony_ci    ASSERT(bc_ins.IsRangeInstruction());
318b1994897Sopenharmony_ci
319b1994897Sopenharmony_ci    uint64_t reg_idx = bc_ins.GetVReg(FIRST_INDEX);
320b1994897Sopenharmony_ci    if (IsRegIdxOutOfBounds(reg_idx, valid_regs_num)) { // for [format: +AA/+AAAA vBB vCC], vBB can be verified here
321b1994897Sopenharmony_ci        return true;
322b1994897Sopenharmony_ci    }
323b1994897Sopenharmony_ci
324b1994897Sopenharmony_ci    std::optional<uint64_t> max_ins_reg_idx_opt = bc_ins.GetRangeInsLastRegIdx();
325b1994897Sopenharmony_ci    if (!max_ins_reg_idx_opt.has_value()) {
326b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Integer overflow detected during register index calculation!";
327b1994897Sopenharmony_ci        return true;
328b1994897Sopenharmony_ci    }
329b1994897Sopenharmony_ci
330b1994897Sopenharmony_ci    reg_idx = max_ins_reg_idx_opt.value();
331b1994897Sopenharmony_ci    if (IsRegIdxOutOfBounds(reg_idx, valid_regs_num)) {
332b1994897Sopenharmony_ci        return true;
333b1994897Sopenharmony_ci    }
334b1994897Sopenharmony_ci
335b1994897Sopenharmony_ci    return false;
336b1994897Sopenharmony_ci}
337b1994897Sopenharmony_ci
338b1994897Sopenharmony_cibool Verifier::IsRegIdxOutOfBounds(uint64_t reg_idx, uint64_t valid_regs_num)
339b1994897Sopenharmony_ci{
340b1994897Sopenharmony_ci    if (reg_idx >= valid_regs_num) {
341b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Register index out of bounds: 0x" << std::hex
342b1994897Sopenharmony_ci                             << reg_idx << ", Max allowed: 0x" << std::hex << valid_regs_num;
343b1994897Sopenharmony_ci        return true;
344b1994897Sopenharmony_ci    }
345b1994897Sopenharmony_ci    return false;
346b1994897Sopenharmony_ci}
347b1994897Sopenharmony_ci
348b1994897Sopenharmony_cibool Verifier::CheckVRegIdx(const BytecodeInstruction &bc_ins, const size_t count, uint64_t valid_regs_num)
349b1994897Sopenharmony_ci{
350b1994897Sopenharmony_ci    if (bc_ins.IsRangeInstruction() &&
351b1994897Sopenharmony_ci        IsRangeInstAndHasInvalidRegIdx(bc_ins, count, valid_regs_num)) {
352b1994897Sopenharmony_ci        return false;
353b1994897Sopenharmony_ci    }
354b1994897Sopenharmony_ci    for (size_t idx = 0; idx < count; idx++) { // Represents the idxTH register index in an instruction
355b1994897Sopenharmony_ci        uint16_t reg_idx = bc_ins.GetVReg(idx);
356b1994897Sopenharmony_ci        if (reg_idx >= valid_regs_num) {
357b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "Register index out of bounds: 0x" << std::hex
358b1994897Sopenharmony_ci                                 << reg_idx << ", Max allowed: 0x" << std::hex << valid_regs_num;
359b1994897Sopenharmony_ci            return false;
360b1994897Sopenharmony_ci        }
361b1994897Sopenharmony_ci    }
362b1994897Sopenharmony_ci    return true;
363b1994897Sopenharmony_ci}
364b1994897Sopenharmony_ci
365b1994897Sopenharmony_cibool Verifier::VerifyMethodId(const uint32_t &method_id) const
366b1994897Sopenharmony_ci{
367b1994897Sopenharmony_ci    auto iter = std::find(constant_pool_ids_.begin(), constant_pool_ids_.end(), method_id);
368b1994897Sopenharmony_ci    if (iter == constant_pool_ids_.end() ||
369b1994897Sopenharmony_ci        (std::find(literal_ids_.begin(), literal_ids_.end(), method_id) != literal_ids_.end()) ||
370b1994897Sopenharmony_ci        ins_string_ids_.count(method_id)) {
371b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Fail to verify method id. method_id(0x" << std::hex << method_id << ")!";
372b1994897Sopenharmony_ci        return false;
373b1994897Sopenharmony_ci    }
374b1994897Sopenharmony_ci    return true;
375b1994897Sopenharmony_ci}
376b1994897Sopenharmony_ci
377b1994897Sopenharmony_cibool Verifier::VerifyLiteralId(const uint32_t &literal_id) const
378b1994897Sopenharmony_ci{
379b1994897Sopenharmony_ci    auto iter = std::find(constant_pool_ids_.begin(), constant_pool_ids_.end(), literal_id);
380b1994897Sopenharmony_ci    if (iter == constant_pool_ids_.end() ||
381b1994897Sopenharmony_ci        (std::find(all_method_ids_.begin(), all_method_ids_.end(), literal_id) != all_method_ids_.end()) ||
382b1994897Sopenharmony_ci        ins_string_ids_.count(literal_id)) {
383b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Fail to verify literal id. literal_id(0x" << std::hex << literal_id << ")!";
384b1994897Sopenharmony_ci        return false;
385b1994897Sopenharmony_ci    }
386b1994897Sopenharmony_ci    return true;
387b1994897Sopenharmony_ci}
388b1994897Sopenharmony_ci
389b1994897Sopenharmony_cibool Verifier::VerifyStringId(const uint32_t &string_id) const
390b1994897Sopenharmony_ci{
391b1994897Sopenharmony_ci    auto iter = std::find(constant_pool_ids_.begin(), constant_pool_ids_.end(), string_id);
392b1994897Sopenharmony_ci    if (iter == constant_pool_ids_.end() ||
393b1994897Sopenharmony_ci        ins_method_ids_.count(string_id) ||
394b1994897Sopenharmony_ci        (std::find(literal_ids_.begin(), literal_ids_.end(), string_id) != literal_ids_.end())) {
395b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Fail to verify string id. string_id(0x" << std::hex << string_id << ")!";
396b1994897Sopenharmony_ci        return false;
397b1994897Sopenharmony_ci    }
398b1994897Sopenharmony_ci    return true;
399b1994897Sopenharmony_ci}
400b1994897Sopenharmony_ci
401b1994897Sopenharmony_cistd::optional<int64_t> Verifier::GetFirstImmFromInstruction(const BytecodeInstruction &bc_ins)
402b1994897Sopenharmony_ci{
403b1994897Sopenharmony_ci    std::optional<int64_t> first_imm = std::optional<int64_t> {};
404b1994897Sopenharmony_ci    size_t index = 0;
405b1994897Sopenharmony_ci    const auto format = bc_ins.GetFormat();
406b1994897Sopenharmony_ci    if (bc_ins.HasImm(format, index)) {
407b1994897Sopenharmony_ci        first_imm = bc_ins.GetImm64(index);
408b1994897Sopenharmony_ci    }
409b1994897Sopenharmony_ci
410b1994897Sopenharmony_ci    return first_imm;
411b1994897Sopenharmony_ci}
412b1994897Sopenharmony_ci
413b1994897Sopenharmony_cistd::optional<uint64_t> Verifier::GetSlotNumberFromAnnotation(panda_file::MethodDataAccessor &method_accessor)
414b1994897Sopenharmony_ci{
415b1994897Sopenharmony_ci    std::optional<uint64_t> slot_number {};
416b1994897Sopenharmony_ci    method_accessor.EnumerateAnnotations([&](panda_file::File::EntityId annotation_id) {
417b1994897Sopenharmony_ci        panda_file::AnnotationDataAccessor ada(*file_, annotation_id);
418b1994897Sopenharmony_ci        auto *annotation_name = reinterpret_cast<const char *>(file_->GetStringData(ada.GetClassId()).data);
419b1994897Sopenharmony_ci        if (::strcmp("L_ESSlotNumberAnnotation;", annotation_name) == 0) {
420b1994897Sopenharmony_ci            uint32_t elem_count = ada.GetCount();
421b1994897Sopenharmony_ci            for (uint32_t i = 0; i < elem_count; i++) {
422b1994897Sopenharmony_ci                panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
423b1994897Sopenharmony_ci                auto *elem_name = reinterpret_cast<const char *>(file_->GetStringData(adae.GetNameId()).data);
424b1994897Sopenharmony_ci                if (::strcmp("SlotNumber", elem_name) == 0) {
425b1994897Sopenharmony_ci                    slot_number = adae.GetScalarValue().GetValue();
426b1994897Sopenharmony_ci                }
427b1994897Sopenharmony_ci            }
428b1994897Sopenharmony_ci        }
429b1994897Sopenharmony_ci    });
430b1994897Sopenharmony_ci    return slot_number;
431b1994897Sopenharmony_ci}
432b1994897Sopenharmony_ci
433b1994897Sopenharmony_cibool Verifier::VerifyMethodIdInLiteralArray(const uint32_t &id)
434b1994897Sopenharmony_ci{
435b1994897Sopenharmony_ci    const auto method_id = panda_file::File::EntityId(id).GetOffset();
436b1994897Sopenharmony_ci    auto iter = std::find(all_method_ids_.begin(), all_method_ids_.end(), method_id);
437b1994897Sopenharmony_ci    if (iter == all_method_ids_.end()) {
438b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Invalid method id(0x" << id << ") in literal array";
439b1994897Sopenharmony_ci        return false;
440b1994897Sopenharmony_ci    }
441b1994897Sopenharmony_ci    return true;
442b1994897Sopenharmony_ci}
443b1994897Sopenharmony_ci
444b1994897Sopenharmony_cibool Verifier::VerifyStringIdInLiteralArray(const uint32_t &id)
445b1994897Sopenharmony_ci{
446b1994897Sopenharmony_ci    auto string_data = file_->GetStringData(panda_file::File::EntityId(id));
447b1994897Sopenharmony_ci    if (string_data.data == nullptr) {
448b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Invalid string_id. string_id(0x" << std::hex << id << ")!";
449b1994897Sopenharmony_ci        return false;
450b1994897Sopenharmony_ci    }
451b1994897Sopenharmony_ci    auto desc = std::string(utf::Mutf8AsCString(string_data.data));
452b1994897Sopenharmony_ci    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
453b1994897Sopenharmony_ci    std::wstring utf16_desc = converter.from_bytes(desc);
454b1994897Sopenharmony_ci    if (string_data.utf16_length != utf16_desc.length()) {
455b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Invalid string value(0x" << id << ") in literal array";
456b1994897Sopenharmony_ci        return false;
457b1994897Sopenharmony_ci    }
458b1994897Sopenharmony_ci    return true;
459b1994897Sopenharmony_ci}
460b1994897Sopenharmony_ci
461b1994897Sopenharmony_cibool Verifier::VerifyLiteralIdInLiteralArray(const uint32_t &id)
462b1994897Sopenharmony_ci{
463b1994897Sopenharmony_ci    auto iter = std::find(literal_ids_.begin(), literal_ids_.end(), id);
464b1994897Sopenharmony_ci    if (iter == literal_ids_.end()) {
465b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Invalid literal id(0x" << id << ") in literal array";
466b1994897Sopenharmony_ci        return false;
467b1994897Sopenharmony_ci    }
468b1994897Sopenharmony_ci    return true;
469b1994897Sopenharmony_ci}
470b1994897Sopenharmony_ci
471b1994897Sopenharmony_cibool Verifier::VerifySingleLiteralArray(const panda_file::File::EntityId &literal_id)
472b1994897Sopenharmony_ci{
473b1994897Sopenharmony_ci    auto sp = file_->GetSpanFromId(literal_id);
474b1994897Sopenharmony_ci    const auto literal_vals_num = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
475b1994897Sopenharmony_ci    for (size_t i = 0; i < literal_vals_num; i += 2U) { // 2u skip literal item
476b1994897Sopenharmony_ci        const auto tag = static_cast<panda_file::LiteralTag>(panda_file::helpers::Read<panda_file::TAG_SIZE>(&sp));
477b1994897Sopenharmony_ci        switch (tag) {
478b1994897Sopenharmony_ci            case panda_file::LiteralTag::TAGVALUE:
479b1994897Sopenharmony_ci            case panda_file::LiteralTag::BOOL:
480b1994897Sopenharmony_ci            case panda_file::LiteralTag::ACCESSOR:
481b1994897Sopenharmony_ci            case panda_file::LiteralTag::NULLVALUE:
482b1994897Sopenharmony_ci            case panda_file::LiteralTag::BUILTINTYPEINDEX: {
483b1994897Sopenharmony_ci                sp = sp.SubSpan(sizeof(uint8_t)); // run next sp
484b1994897Sopenharmony_ci                break;
485b1994897Sopenharmony_ci            }
486b1994897Sopenharmony_ci            case panda_file::LiteralTag::METHODAFFILIATE: {
487b1994897Sopenharmony_ci                sp = sp.SubSpan(sizeof(uint16_t));
488b1994897Sopenharmony_ci                break;
489b1994897Sopenharmony_ci            }
490b1994897Sopenharmony_ci            case panda_file::LiteralTag::INTEGER:
491b1994897Sopenharmony_ci            case panda_file::LiteralTag::FLOAT:
492b1994897Sopenharmony_ci            case panda_file::LiteralTag::GETTER:
493b1994897Sopenharmony_ci            case panda_file::LiteralTag::SETTER:
494b1994897Sopenharmony_ci            case panda_file::LiteralTag::GENERATORMETHOD:
495b1994897Sopenharmony_ci            case panda_file::LiteralTag::LITERALBUFFERINDEX:
496b1994897Sopenharmony_ci            case panda_file::LiteralTag::ASYNCGENERATORMETHOD: {
497b1994897Sopenharmony_ci                sp = sp.SubSpan(sizeof(uint32_t));
498b1994897Sopenharmony_ci                break;
499b1994897Sopenharmony_ci            }
500b1994897Sopenharmony_ci            case panda_file::LiteralTag::DOUBLE: {
501b1994897Sopenharmony_ci                const auto value = bit_cast<double>(panda_file::helpers::Read<sizeof(uint64_t)>(&sp));
502b1994897Sopenharmony_ci                // true: High 16-bit of double value >= 0xffff
503b1994897Sopenharmony_ci                if (IsImpureNaN(value)) {
504b1994897Sopenharmony_ci                    LOG(ERROR, VERIFIER) << "Fail to verify double value " << value << " in literal array";
505b1994897Sopenharmony_ci                    return false;
506b1994897Sopenharmony_ci                }
507b1994897Sopenharmony_ci                break;
508b1994897Sopenharmony_ci            }
509b1994897Sopenharmony_ci            case panda_file::LiteralTag::ARRAY_U1:
510b1994897Sopenharmony_ci            case panda_file::LiteralTag::ARRAY_U8:
511b1994897Sopenharmony_ci            case panda_file::LiteralTag::ARRAY_I8:
512b1994897Sopenharmony_ci            case panda_file::LiteralTag::ARRAY_U16:
513b1994897Sopenharmony_ci            case panda_file::LiteralTag::ARRAY_I16:
514b1994897Sopenharmony_ci            case panda_file::LiteralTag::ARRAY_U32:
515b1994897Sopenharmony_ci            case panda_file::LiteralTag::ARRAY_I32:
516b1994897Sopenharmony_ci            case panda_file::LiteralTag::ARRAY_U64:
517b1994897Sopenharmony_ci            case panda_file::LiteralTag::ARRAY_I64:
518b1994897Sopenharmony_ci            case panda_file::LiteralTag::ARRAY_F32:
519b1994897Sopenharmony_ci            case panda_file::LiteralTag::ARRAY_F64:
520b1994897Sopenharmony_ci            case panda_file::LiteralTag::ARRAY_STRING: {
521b1994897Sopenharmony_ci                i = literal_vals_num;
522b1994897Sopenharmony_ci                break;
523b1994897Sopenharmony_ci            }
524b1994897Sopenharmony_ci            case panda_file::LiteralTag::STRING: {
525b1994897Sopenharmony_ci                panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
526b1994897Sopenharmony_ci                break;
527b1994897Sopenharmony_ci            }
528b1994897Sopenharmony_ci            case panda_file::LiteralTag::METHOD: {
529b1994897Sopenharmony_ci                const auto value = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint32_t)>(&sp));
530b1994897Sopenharmony_ci                inner_method_map_.emplace(literal_id.GetOffset(), value);
531b1994897Sopenharmony_ci                if (!VerifyMethodIdInLiteralArray(value)) {
532b1994897Sopenharmony_ci                    return false;
533b1994897Sopenharmony_ci                }
534b1994897Sopenharmony_ci                break;
535b1994897Sopenharmony_ci            }
536b1994897Sopenharmony_ci            case panda_file::LiteralTag::LITERALARRAY: {
537b1994897Sopenharmony_ci                const auto value = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint32_t)>(&sp));
538b1994897Sopenharmony_ci                inner_literal_map_.emplace(literal_id.GetOffset(), value);
539b1994897Sopenharmony_ci                if (!VerifyLiteralIdInLiteralArray(value)) {
540b1994897Sopenharmony_ci                    return false;
541b1994897Sopenharmony_ci                }
542b1994897Sopenharmony_ci                break;
543b1994897Sopenharmony_ci            }
544b1994897Sopenharmony_ci            default: {
545b1994897Sopenharmony_ci                LOG(ERROR, VERIFIER) << "Invalid literal tag";
546b1994897Sopenharmony_ci                return false;
547b1994897Sopenharmony_ci            }
548b1994897Sopenharmony_ci        }
549b1994897Sopenharmony_ci    }
550b1994897Sopenharmony_ci    return true;
551b1994897Sopenharmony_ci}
552b1994897Sopenharmony_ci
553b1994897Sopenharmony_cibool Verifier::IsModuleLiteralId(const panda_file::File::EntityId &id) const
554b1994897Sopenharmony_ci{
555b1994897Sopenharmony_ci    return module_literals_.find(id.GetOffset()) != module_literals_.end();
556b1994897Sopenharmony_ci}
557b1994897Sopenharmony_ci
558b1994897Sopenharmony_cibool Verifier::VerifyLiteralArrays()
559b1994897Sopenharmony_ci{
560b1994897Sopenharmony_ci    for (const auto &arg_literal_id : literal_ids_) {
561b1994897Sopenharmony_ci        const auto literal_id = panda_file::File::EntityId(arg_literal_id);
562b1994897Sopenharmony_ci        if (!IsModuleLiteralId(literal_id) && !VerifySingleLiteralArray(literal_id)) {
563b1994897Sopenharmony_ci            return false;
564b1994897Sopenharmony_ci        }
565b1994897Sopenharmony_ci    }
566b1994897Sopenharmony_ci    return true;
567b1994897Sopenharmony_ci}
568b1994897Sopenharmony_ci
569b1994897Sopenharmony_cibool Verifier::PrecomputeInstructionIndices(const BytecodeInstruction &bc_ins_start,
570b1994897Sopenharmony_ci                                            const BytecodeInstruction &bc_ins_last)
571b1994897Sopenharmony_ci{
572b1994897Sopenharmony_ci    instruction_index_map_.clear();
573b1994897Sopenharmony_ci    size_t index = 0;
574b1994897Sopenharmony_ci    auto current_ins = bc_ins_start;
575b1994897Sopenharmony_ci    instruction_index_map_[current_ins.GetAddress()] = index;
576b1994897Sopenharmony_ci
577b1994897Sopenharmony_ci    while (current_ins.GetAddress() < bc_ins_last.GetAddress()) {
578b1994897Sopenharmony_ci        //Must keep IsPrimaryOpcodeValid is the first check item
579b1994897Sopenharmony_ci        if (!current_ins.IsPrimaryOpcodeValid()) {
580b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "Fail to verify primary opcode!";
581b1994897Sopenharmony_ci            return false;
582b1994897Sopenharmony_ci        }
583b1994897Sopenharmony_ci        current_ins = current_ins.GetNext();
584b1994897Sopenharmony_ci        index++;
585b1994897Sopenharmony_ci        instruction_index_map_[current_ins.GetAddress()] = index;
586b1994897Sopenharmony_ci    }
587b1994897Sopenharmony_ci    return true;
588b1994897Sopenharmony_ci}
589b1994897Sopenharmony_ci
590b1994897Sopenharmony_cibool Verifier::IsMethodBytecodeInstruction(const BytecodeInstruction &bc_ins_cur)
591b1994897Sopenharmony_ci{
592b1994897Sopenharmony_ci    if (instruction_index_map_.find(bc_ins_cur.GetAddress()) != instruction_index_map_.end()) {
593b1994897Sopenharmony_ci        return true;
594b1994897Sopenharmony_ci    }
595b1994897Sopenharmony_ci    return false;
596b1994897Sopenharmony_ci}
597b1994897Sopenharmony_ci
598b1994897Sopenharmony_cibool Verifier::VerifyJumpInstruction(const BytecodeInstruction &bc_ins, const BytecodeInstruction &bc_ins_last,
599b1994897Sopenharmony_ci                                     const BytecodeInstruction &bc_ins_first, const uint8_t *ins_arr,
600b1994897Sopenharmony_ci                                     panda_file::File::EntityId code_id)
601b1994897Sopenharmony_ci{
602b1994897Sopenharmony_ci    // update maximum forward offset
603b1994897Sopenharmony_ci    const auto bc_ins_forward_size = bc_ins_last.GetAddress() - bc_ins.GetAddress();
604b1994897Sopenharmony_ci    // update maximum backward offset
605b1994897Sopenharmony_ci    const auto bc_ins_backward_size = bc_ins.GetAddress() - bc_ins_first.GetAddress();
606b1994897Sopenharmony_ci
607b1994897Sopenharmony_ci    if (bc_ins.IsJumpInstruction()) {
608b1994897Sopenharmony_ci        std::optional<int64_t> immdata = GetFirstImmFromInstruction(bc_ins);
609b1994897Sopenharmony_ci        if (!immdata.has_value()) {
610b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "Fail to get immediate data!";
611b1994897Sopenharmony_ci            return false;
612b1994897Sopenharmony_ci        }
613b1994897Sopenharmony_ci        if ((immdata.value() > 0) && (immdata.value() >= bc_ins_forward_size)) {
614b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "Jump forward out of boundary";
615b1994897Sopenharmony_ci            return false;
616b1994897Sopenharmony_ci        }
617b1994897Sopenharmony_ci        if ((immdata.value() < 0) && (bc_ins_backward_size + immdata.value() < 0)) {
618b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "Jump backward out of boundary";
619b1994897Sopenharmony_ci            return false;
620b1994897Sopenharmony_ci        }
621b1994897Sopenharmony_ci
622b1994897Sopenharmony_ci        const auto bc_ins_dest = bc_ins.JumpTo(immdata.value());
623b1994897Sopenharmony_ci        if (!bc_ins_dest.IsPrimaryOpcodeValid()) {
624b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "Fail to verify target jump primary opcode!";
625b1994897Sopenharmony_ci            return false;
626b1994897Sopenharmony_ci        }
627b1994897Sopenharmony_ci        if (!IsMethodBytecodeInstruction(bc_ins_dest)) {
628b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "> error encountered at " << code_id << " (0x" << std::hex << code_id
629b1994897Sopenharmony_ci                                 << "). incorrect instruction at offset: 0x" << (bc_ins.GetAddress() - ins_arr)
630b1994897Sopenharmony_ci                                 << ": invalid jump offset 0x" << immdata.value()
631b1994897Sopenharmony_ci                                 << " - jumping in the middle of another instruction!";
632b1994897Sopenharmony_ci            return false;
633b1994897Sopenharmony_ci        }
634b1994897Sopenharmony_ci    }
635b1994897Sopenharmony_ci
636b1994897Sopenharmony_ci    return true;
637b1994897Sopenharmony_ci}
638b1994897Sopenharmony_ci
639b1994897Sopenharmony_cibool Verifier::GetIcSlotFromInstruction(const BytecodeInstruction &bc_ins, uint32_t &first_slot_index,
640b1994897Sopenharmony_ci                                        bool &has_slot, bool &is_two_slot)
641b1994897Sopenharmony_ci{
642b1994897Sopenharmony_ci    std::optional<uint64_t> first_imm = {};
643b1994897Sopenharmony_ci    if (bc_ins.HasFlag(BytecodeInstruction::Flags::ONE_SLOT)) {
644b1994897Sopenharmony_ci        first_imm = GetFirstImmFromInstruction(bc_ins);
645b1994897Sopenharmony_ci        if (!first_imm.has_value()) {
646b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "Fail to get first immediate data!";
647b1994897Sopenharmony_ci            return false;
648b1994897Sopenharmony_ci        }
649b1994897Sopenharmony_ci        first_slot_index = first_imm.value();
650b1994897Sopenharmony_ci        is_two_slot = false;
651b1994897Sopenharmony_ci        has_slot = true;
652b1994897Sopenharmony_ci    } else if (bc_ins.HasFlag(BytecodeInstruction::Flags::TWO_SLOT)) {
653b1994897Sopenharmony_ci        first_imm = GetFirstImmFromInstruction(bc_ins);
654b1994897Sopenharmony_ci        if (!first_imm.has_value()) {
655b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "Fail to get first immediate data!";
656b1994897Sopenharmony_ci            return false;
657b1994897Sopenharmony_ci        }
658b1994897Sopenharmony_ci        first_slot_index = first_imm.value();
659b1994897Sopenharmony_ci        has_slot = true;
660b1994897Sopenharmony_ci        is_two_slot = true;
661b1994897Sopenharmony_ci    }
662b1994897Sopenharmony_ci
663b1994897Sopenharmony_ci    return true;
664b1994897Sopenharmony_ci}
665b1994897Sopenharmony_ci
666b1994897Sopenharmony_cibool Verifier::VerifyCatchBlocks(panda_file::CodeDataAccessor::TryBlock &try_block, const BytecodeInstruction &bc_ins,
667b1994897Sopenharmony_ci                                 const BytecodeInstruction &bc_ins_last)
668b1994897Sopenharmony_ci{
669b1994897Sopenharmony_ci    bool result = true;
670b1994897Sopenharmony_ci
671b1994897Sopenharmony_ci    try_block.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catch_block) {
672b1994897Sopenharmony_ci        const auto handler_begin_offset = catch_block.GetHandlerPc();
673b1994897Sopenharmony_ci        // GetCodeSize() returns a unsigned long value, which is always >= 0,
674b1994897Sopenharmony_ci        // so handler_end_offset is guaranteed to be >= handler_begin_offset
675b1994897Sopenharmony_ci        const auto handler_end_offset = handler_begin_offset + catch_block.GetCodeSize();
676b1994897Sopenharmony_ci
677b1994897Sopenharmony_ci        const auto handler_begin_bc_ins = bc_ins.JumpTo(handler_begin_offset);
678b1994897Sopenharmony_ci        const auto handler_end_bc_ins = bc_ins.JumpTo(handler_end_offset);
679b1994897Sopenharmony_ci
680b1994897Sopenharmony_ci        const bool handler_begin_offset_in_range = bc_ins_last.GetAddress() > handler_begin_bc_ins.GetAddress();
681b1994897Sopenharmony_ci        const bool handler_end_offset_in_range = bc_ins_last.GetAddress() >= handler_end_bc_ins.GetAddress();
682b1994897Sopenharmony_ci
683b1994897Sopenharmony_ci        if (!handler_begin_offset_in_range) {
684b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "> Invalid catch block begin offset range! address is: 0x" << std::hex
685b1994897Sopenharmony_ci                                 << handler_begin_bc_ins.GetAddress();
686b1994897Sopenharmony_ci            result = false;
687b1994897Sopenharmony_ci            return false;
688b1994897Sopenharmony_ci        }
689b1994897Sopenharmony_ci        if (!IsMethodBytecodeInstruction(handler_begin_bc_ins)) {
690b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "> Invalid catch block begin offset validity! address is: 0x" << std::hex
691b1994897Sopenharmony_ci                                 << handler_begin_bc_ins.GetAddress();
692b1994897Sopenharmony_ci            result = false;
693b1994897Sopenharmony_ci            return false;
694b1994897Sopenharmony_ci        }
695b1994897Sopenharmony_ci        if (!handler_end_offset_in_range) {
696b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "> Invalid catch block end offset range! address is: 0x" << std::hex
697b1994897Sopenharmony_ci                                 << handler_end_bc_ins.GetAddress();
698b1994897Sopenharmony_ci            result = false;
699b1994897Sopenharmony_ci            return false;
700b1994897Sopenharmony_ci        }
701b1994897Sopenharmony_ci        if (!IsMethodBytecodeInstruction(handler_end_bc_ins)) {
702b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "> Invalid catch block end offset validity! address is: 0x" << std::hex
703b1994897Sopenharmony_ci                                 << handler_end_bc_ins.GetAddress();
704b1994897Sopenharmony_ci            result = false;
705b1994897Sopenharmony_ci            return false;
706b1994897Sopenharmony_ci        }
707b1994897Sopenharmony_ci
708b1994897Sopenharmony_ci        return true;
709b1994897Sopenharmony_ci    });
710b1994897Sopenharmony_ci
711b1994897Sopenharmony_ci    return result;
712b1994897Sopenharmony_ci}
713b1994897Sopenharmony_ci
714b1994897Sopenharmony_cibool Verifier::VerifyTryBlocks(panda_file::CodeDataAccessor &code_accessor, const BytecodeInstruction &bc_ins,
715b1994897Sopenharmony_ci                               const BytecodeInstruction &bc_ins_last)
716b1994897Sopenharmony_ci{
717b1994897Sopenharmony_ci    bool result = true;
718b1994897Sopenharmony_ci
719b1994897Sopenharmony_ci    code_accessor.EnumerateTryBlocks([&](panda_file::CodeDataAccessor::TryBlock &try_block) {
720b1994897Sopenharmony_ci        const auto try_begin_bc_ins = bc_ins.JumpTo(try_block.GetStartPc());
721b1994897Sopenharmony_ci        // GetLength() returns a uint32 value, which is always >= 0,
722b1994897Sopenharmony_ci        // so try_end_bc_ins is guaranteed to be >= try_begin_bc_ins
723b1994897Sopenharmony_ci        const auto try_end_bc_ins = bc_ins.JumpTo(try_block.GetStartPc() + try_block.GetLength());
724b1994897Sopenharmony_ci
725b1994897Sopenharmony_ci        const bool try_begin_offset_in_range = bc_ins_last.GetAddress() > try_begin_bc_ins.GetAddress();
726b1994897Sopenharmony_ci        const bool try_end_offset_in_range = bc_ins_last.GetAddress() >= try_end_bc_ins.GetAddress();
727b1994897Sopenharmony_ci
728b1994897Sopenharmony_ci        if (!try_begin_offset_in_range) {
729b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "> Invalid try block begin offset range! address is: 0x" << std::hex
730b1994897Sopenharmony_ci                                 << try_begin_bc_ins.GetAddress();
731b1994897Sopenharmony_ci            result = false;
732b1994897Sopenharmony_ci            return false;
733b1994897Sopenharmony_ci        }
734b1994897Sopenharmony_ci        if (!IsMethodBytecodeInstruction(try_begin_bc_ins)) {
735b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "> Invalid try block begin offset validity! address is: 0x" << std::hex
736b1994897Sopenharmony_ci                                 << try_begin_bc_ins.GetAddress();
737b1994897Sopenharmony_ci            result = false;
738b1994897Sopenharmony_ci            return false;
739b1994897Sopenharmony_ci        }
740b1994897Sopenharmony_ci        if (!try_end_offset_in_range) {
741b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "> Invalid try block end offset range! address is: 0x" << std::hex
742b1994897Sopenharmony_ci                                 << try_end_bc_ins.GetAddress();
743b1994897Sopenharmony_ci            result = false;
744b1994897Sopenharmony_ci            return false;
745b1994897Sopenharmony_ci        }
746b1994897Sopenharmony_ci        if (!IsMethodBytecodeInstruction(try_end_bc_ins)) {
747b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "> Invalid try block end offset validity! address is: 0x" << std::hex
748b1994897Sopenharmony_ci                                 << try_end_bc_ins.GetAddress();
749b1994897Sopenharmony_ci            result = false;
750b1994897Sopenharmony_ci            return false;
751b1994897Sopenharmony_ci        }
752b1994897Sopenharmony_ci        if (!VerifyCatchBlocks(try_block, bc_ins, bc_ins_last)) {
753b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "Catch block validation failed!";
754b1994897Sopenharmony_ci            result = false;
755b1994897Sopenharmony_ci            return false;
756b1994897Sopenharmony_ci        }
757b1994897Sopenharmony_ci
758b1994897Sopenharmony_ci        return true;
759b1994897Sopenharmony_ci    });
760b1994897Sopenharmony_ci
761b1994897Sopenharmony_ci    return result;
762b1994897Sopenharmony_ci}
763b1994897Sopenharmony_ci
764b1994897Sopenharmony_ci
765b1994897Sopenharmony_cibool Verifier::VerifySlotNumber(panda_file::MethodDataAccessor &method_accessor, const uint32_t &slot_number,
766b1994897Sopenharmony_ci                                const panda_file::File::EntityId &method_id)
767b1994897Sopenharmony_ci{
768b1994897Sopenharmony_ci    const auto ann_slot_number = GetSlotNumberFromAnnotation(method_accessor);
769b1994897Sopenharmony_ci    if (!ann_slot_number.has_value()) {
770b1994897Sopenharmony_ci        LOG(INFO, VERIFIER) << "There is no slot number information in annotaion.";
771b1994897Sopenharmony_ci        // To be compatible with old abc, slot number verification is not continued
772b1994897Sopenharmony_ci        return true;
773b1994897Sopenharmony_ci    }
774b1994897Sopenharmony_ci    if (slot_number == ann_slot_number.value()) {
775b1994897Sopenharmony_ci        return true;
776b1994897Sopenharmony_ci    }
777b1994897Sopenharmony_ci
778b1994897Sopenharmony_ci    LOG(ERROR, VERIFIER) << "Slot number has been falsified in method 0x" << method_id;
779b1994897Sopenharmony_ci    return false;
780b1994897Sopenharmony_ci}
781b1994897Sopenharmony_ci
782b1994897Sopenharmony_cibool Verifier::VerifyMethodRegisterIndex(panda_file::CodeDataAccessor &code_accessor,
783b1994897Sopenharmony_ci                                         std::optional<uint64_t> &valid_regs_num)
784b1994897Sopenharmony_ci{
785b1994897Sopenharmony_ci    const uint64_t reg_nums = code_accessor.GetNumVregs();
786b1994897Sopenharmony_ci    const uint64_t arg_nums = code_accessor.GetNumArgs();
787b1994897Sopenharmony_ci    valid_regs_num = SafeAdd(reg_nums, arg_nums);
788b1994897Sopenharmony_ci    if (!valid_regs_num.has_value()) {
789b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Integer overflow detected during register index calculation!";
790b1994897Sopenharmony_ci        return false;
791b1994897Sopenharmony_ci    }
792b1994897Sopenharmony_ci    if (valid_regs_num.value() > MAX_REGISTER_INDEX + 1) {
793b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Register index exceeds the maximum allowable value (0xffff)!";
794b1994897Sopenharmony_ci        return false;
795b1994897Sopenharmony_ci    }
796b1994897Sopenharmony_ci    return true;
797b1994897Sopenharmony_ci}
798b1994897Sopenharmony_ci
799b1994897Sopenharmony_cibool Verifier::VerifyMethodInstructions(const MethodInfos &infos)
800b1994897Sopenharmony_ci{
801b1994897Sopenharmony_ci    auto current_ins = infos.bc_ins;
802b1994897Sopenharmony_ci    auto last_ins = infos.bc_ins_last;
803b1994897Sopenharmony_ci    auto code_id = infos.method_accessor.GetCodeId().value();
804b1994897Sopenharmony_ci    auto method_id = infos.method_id;
805b1994897Sopenharmony_ci    auto valid_regs_num = infos.valid_regs_num.value();
806b1994897Sopenharmony_ci    auto ins_slot_num = infos.ins_slot_num;
807b1994897Sopenharmony_ci    auto has_slot = infos.has_slot;
808b1994897Sopenharmony_ci    auto is_two_slot = infos.is_two_slot;
809b1994897Sopenharmony_ci
810b1994897Sopenharmony_ci    while (current_ins.GetAddress() != last_ins.GetAddress()) {
811b1994897Sopenharmony_ci        if (current_ins.GetAddress() > last_ins.GetAddress()) {
812b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "> error encountered at " << code_id
813b1994897Sopenharmony_ci                                 << " (0x" << std::hex << code_id
814b1994897Sopenharmony_ci                                 << "). bytecode instructions sequence corrupted for method "
815b1994897Sopenharmony_ci                                 << method_id
816b1994897Sopenharmony_ci                                 << "! went out of bounds";
817b1994897Sopenharmony_ci            return false;
818b1994897Sopenharmony_ci        }
819b1994897Sopenharmony_ci        if (!current_ins.IsJumpInstruction() && !current_ins.IsReturnOrThrowInstruction()
820b1994897Sopenharmony_ci            && current_ins.GetNext().GetAddress() == last_ins.GetAddress()) {
821b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "> error encountered at " << code_id
822b1994897Sopenharmony_ci                                 << " (0x" << std::hex << code_id
823b1994897Sopenharmony_ci                                 << "). bytecode instructions sequence corrupted for method "
824b1994897Sopenharmony_ci                                 << method_id
825b1994897Sopenharmony_ci                                 << "! went out of bounds";
826b1994897Sopenharmony_ci            return false;
827b1994897Sopenharmony_ci        }
828b1994897Sopenharmony_ci        const size_t count = GetVRegCount(current_ins);
829b1994897Sopenharmony_ci        if (count != 0 && !CheckVRegIdx(current_ins, count, valid_regs_num)) {
830b1994897Sopenharmony_ci            return false;
831b1994897Sopenharmony_ci        }
832b1994897Sopenharmony_ci        if (!VerifyJumpInstruction(current_ins, last_ins,
833b1994897Sopenharmony_ci                                   infos.bc_ins_init, infos.ins_arr,
834b1994897Sopenharmony_ci                                   code_id)) {
835b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "Invalid target position of jump instruction";
836b1994897Sopenharmony_ci            return false;
837b1994897Sopenharmony_ci        }
838b1994897Sopenharmony_ci        if (!GetIcSlotFromInstruction(current_ins, ins_slot_num,
839b1994897Sopenharmony_ci                                      has_slot, is_two_slot)) {
840b1994897Sopenharmony_ci            LOG(ERROR, VERIFIER) << "Fail to get first slot index!";
841b1994897Sopenharmony_ci            return false;
842b1994897Sopenharmony_ci        }
843b1994897Sopenharmony_ci        current_ins = current_ins.GetNext();
844b1994897Sopenharmony_ci    }
845b1994897Sopenharmony_ci    return true;
846b1994897Sopenharmony_ci}
847b1994897Sopenharmony_ci
848b1994897Sopenharmony_cibool Verifier::CheckConstantPoolMethodContent(const panda_file::File::EntityId &method_id)
849b1994897Sopenharmony_ci{
850b1994897Sopenharmony_ci    panda_file::MethodDataAccessor method_accessor(*file_, method_id);
851b1994897Sopenharmony_ci    if (!method_accessor.GetCodeId().has_value()) {
852b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Fail to get code id!";
853b1994897Sopenharmony_ci        return false;
854b1994897Sopenharmony_ci    }
855b1994897Sopenharmony_ci    panda_file::CodeDataAccessor code_accessor(*file_, method_accessor.GetCodeId().value());
856b1994897Sopenharmony_ci    const auto ins_size = code_accessor.GetCodeSize();
857b1994897Sopenharmony_ci    const auto ins_arr = code_accessor.GetInstructions();
858b1994897Sopenharmony_ci    auto bc_ins = BytecodeInstruction(ins_arr);
859b1994897Sopenharmony_ci    const auto bc_ins_last = bc_ins.JumpTo(ins_size);
860b1994897Sopenharmony_ci    const auto bc_ins_init = bc_ins; // initial PC value
861b1994897Sopenharmony_ci    uint32_t ins_slot_num = 0; // For ic slot index verification
862b1994897Sopenharmony_ci    bool has_slot = false;
863b1994897Sopenharmony_ci    bool is_two_slot = false;
864b1994897Sopenharmony_ci    std::optional<uint64_t> valid_regs_num = 0;
865b1994897Sopenharmony_ci    MethodInfos infos = {bc_ins_init, bc_ins, bc_ins_last, method_accessor, method_id,
866b1994897Sopenharmony_ci                         valid_regs_num, ins_arr, ins_slot_num, has_slot, is_two_slot};
867b1994897Sopenharmony_ci    if (ins_size <= 0) {
868b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Fail to verify code size!";
869b1994897Sopenharmony_ci        return false;
870b1994897Sopenharmony_ci    }
871b1994897Sopenharmony_ci    if (!VerifyMethodRegisterIndex(code_accessor, valid_regs_num)) {
872b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Fail to verify method register index!";
873b1994897Sopenharmony_ci        return false;
874b1994897Sopenharmony_ci    }
875b1994897Sopenharmony_ci    if (!PrecomputeInstructionIndices(bc_ins, bc_ins_last)) {
876b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Fail to precompute instruction indices!";
877b1994897Sopenharmony_ci        return false;
878b1994897Sopenharmony_ci    }
879b1994897Sopenharmony_ci    if (!IsMethodBytecodeInstruction(bc_ins)) {
880b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Fail to verify method first bytecode instruction!";
881b1994897Sopenharmony_ci    }
882b1994897Sopenharmony_ci    if (!VerifyTryBlocks(code_accessor, bc_ins, bc_ins_last)) {
883b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Fail to verify try blocks or catch blocks!";
884b1994897Sopenharmony_ci        return false;
885b1994897Sopenharmony_ci    }
886b1994897Sopenharmony_ci    if (!VerifyMethodInstructions(infos)) {
887b1994897Sopenharmony_ci        LOG(ERROR, VERIFIER) << "Fail to verify method instructions!";
888b1994897Sopenharmony_ci        return false;
889b1994897Sopenharmony_ci    }
890b1994897Sopenharmony_ci    if (has_slot) {
891b1994897Sopenharmony_ci        if (is_two_slot) {
892b1994897Sopenharmony_ci            ins_slot_num += 1; // when there are two slots for the last instruction, the slot index increases
893b1994897Sopenharmony_ci        }
894b1994897Sopenharmony_ci        ins_slot_num += 1; // slot index starts with zero
895b1994897Sopenharmony_ci    }
896b1994897Sopenharmony_ci    return true;
897b1994897Sopenharmony_ci}
898b1994897Sopenharmony_ci
899b1994897Sopenharmony_cibool Verifier::CheckConstantPoolIndex() const
900b1994897Sopenharmony_ci{
901b1994897Sopenharmony_ci    for (auto &id : ins_method_ids_) {
902b1994897Sopenharmony_ci        if (!VerifyMethodId(id)) {
903b1994897Sopenharmony_ci            return false;
904b1994897Sopenharmony_ci        }
905b1994897Sopenharmony_ci    }
906b1994897Sopenharmony_ci
907b1994897Sopenharmony_ci    for (auto &id : ins_literal_ids_) {
908b1994897Sopenharmony_ci        if (!VerifyLiteralId(id)) {
909b1994897Sopenharmony_ci            return false;
910b1994897Sopenharmony_ci        }
911b1994897Sopenharmony_ci    }
912b1994897Sopenharmony_ci
913b1994897Sopenharmony_ci    for (auto &id : ins_string_ids_) {
914b1994897Sopenharmony_ci        if (!VerifyStringId(id)) {
915b1994897Sopenharmony_ci            return false;
916b1994897Sopenharmony_ci        }
917b1994897Sopenharmony_ci    }
918b1994897Sopenharmony_ci
919b1994897Sopenharmony_ci    return true;
920b1994897Sopenharmony_ci}
921b1994897Sopenharmony_ci
922b1994897Sopenharmony_cistd::optional<uint64_t> Verifier::SafeAdd(uint64_t a, uint64_t b) const
923b1994897Sopenharmony_ci{
924b1994897Sopenharmony_ci    if (a > std::numeric_limits<uint64_t>::max() - b) {
925b1994897Sopenharmony_ci        return std::nullopt;
926b1994897Sopenharmony_ci    }
927b1994897Sopenharmony_ci    return a + b;
928b1994897Sopenharmony_ci}
929b1994897Sopenharmony_ci} // namespace panda::verifier
930