• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "bytecode_instruction-inl.h"
17 #include "file_items.h"
18 #include "macros.h"
19 #include "include/runtime.h"
20 #include "runtime/include/thread_scopes.h"
21 #include "runtime/include/method-inl.h"
22 
23 #include "utils/logger.h"
24 
25 #include "util/str.h"
26 
27 #include "cflow_info.h"
28 
29 #include <iomanip>
30 
31 #include "cflow_iterate_inl.h"
32 
33 #include "verification/jobs/job.h"
34 #include "verification/cflow/cflow_common.h"
35 #include "verification/public_internal.h"
36 #include "verification/verification_status.h"
37 
38 #include "verifier_messages.h"
39 
40 namespace ark::verifier {
41 
FillCodeMaps(Method const * method)42 VerificationStatus CflowMethodInfo::FillCodeMaps(Method const *method)
43 {
44     auto status = IterateOverInstructions(
45         addrStart_, addrStart_, addrEnd_,
46         [this, method]([[maybe_unused]] auto typ, uint8_t const *pc, size_t sz, bool exceptionSource,
47                        [[maybe_unused]] auto tgt) -> std::optional<VerificationStatus> {
48             SetFlag(pc, INSTRUCTION);
49             if (exceptionSource) {
50                 SetFlag(pc, EXCEPTION_SOURCE);
51             }
52             if (tgt != nullptr) {  // a jump
53                 if (!IsAddrValid(tgt)) {
54                     LOG_VERIFIER_CFLOW_INVALID_JUMP_OUTSIDE_METHOD_BODY(
55                         method->GetFullName(), OffsetAsHexStr(addrStart_, tgt), OffsetAsHexStr(addrStart_, pc));
56                     return VerificationStatus::ERROR;
57                 }
58                 SetFlag(tgt, JUMP_TARGET);
59             }
60             uint8_t const *nextInstPc = &pc[sz];  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
61             if (nextInstPc == addrEnd_) {
62                 return VerificationStatus::OK;
63             }
64             if (nextInstPc > addrEnd_) {
65                 LOG_VERIFIER_CFLOW_INVALID_INSTRUCTION(OffsetAsHexStr(addrStart_, pc));
66                 return VerificationStatus::ERROR;
67             }
68             return std::nullopt;
69         });
70     return status;
71 }
72 
ProcessCatchBlocks(Method const * method)73 VerificationStatus CflowMethodInfo::ProcessCatchBlocks(Method const *method)
74 {
75     using CatchBlock = panda_file::CodeDataAccessor::CatchBlock;
76 
77     LOG(DEBUG, VERIFIER) << "Tracing exception handlers.";
78 
79     auto status = VerificationStatus::OK;
80     method->EnumerateCatchBlocks([&]([[maybe_unused]] uint8_t const *tryStartPc,
81                                      [[maybe_unused]] uint8_t const *tryEndPc, CatchBlock const &catchBlock) {
82         auto catchBlockStart = reinterpret_cast<uint8_t const *>(reinterpret_cast<uintptr_t>(addrStart_) +
83                                                                  static_cast<uintptr_t>(catchBlock.GetHandlerPc()));
84         auto catchBlockEnd =
85             &catchBlockStart[catchBlock.GetCodeSize()];  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
86         if (catchBlockStart > catchBlockEnd || catchBlockStart >= addrEnd_ || catchBlockEnd < addrStart_) {
87             LOG_VERIFIER_CFLOW_BAD_CATCH_BLOCK_BOUNDARIES(OffsetAsHexStr(addrStart_, catchBlockStart),
88                                                           OffsetAsHexStr(addrStart_, catchBlockEnd));
89             status = VerificationStatus::ERROR;
90             return false;
91         }
92         if (catchBlockEnd == catchBlockStart) {
93             // special case, no need to iterate over instructions.
94             return true;
95         }
96 
97         handlerStartAddresses_.push_back(catchBlockStart);
98 
99         auto result = IterateOverInstructions(
100             catchBlockStart, addrStart_, addrEnd_,
101             [this, catchBlockEnd]([[maybe_unused]] auto typ, uint8_t const *pc, size_t sz,
102                                   [[maybe_unused]] bool exceptionSource,
103                                   [[maybe_unused]] auto tgt) -> std::optional<VerificationStatus> {
104                 SetFlag(pc, EXCEPTION_HANDLER);
105                 uint8_t const *nextInstPc = &pc[sz];  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
106                 if (nextInstPc == catchBlockEnd) {
107                     return VerificationStatus::OK;
108                 }
109                 if (nextInstPc > catchBlockEnd) {
110                     LOG_VERIFIER_CFLOW_INVALID_INSTRUCTION(OffsetAsHexStr(addrStart_, pc));
111                     return VerificationStatus::ERROR;
112                 }
113                 return std::nullopt;
114             });
115         status = std::max(status, result);
116         return true;
117     });
118 
119     // Serves as a barrier
120     auto endCode = reinterpret_cast<uint8_t const *>(reinterpret_cast<uintptr_t>(method->GetInstructions()) +
121                                                      method->GetCodeSize());
122     handlerStartAddresses_.push_back(endCode);
123     std::sort(handlerStartAddresses_.begin(), handlerStartAddresses_.end());
124 
125     return status;
126 }
127 
GetCflowMethodInfo(Method const * method)128 PandaUniquePtr<CflowMethodInfo> GetCflowMethodInfo(Method const *method)
129 {
130     const uint8_t *methodPcStartPtr = method->GetInstructions();
131     size_t codeSize = method->GetCodeSize();
132 
133     auto cflowInfo = MakePandaUnique<CflowMethodInfo>(methodPcStartPtr, codeSize);
134 
135     LOG(DEBUG, VERIFIER) << "Build control flow info for method " << method->GetFullName();
136 
137     // 1. fill instructions map
138     LOG(DEBUG, VERIFIER) << "Build instructions map.";
139     if (cflowInfo == nullptr) {
140         LOG(ERROR, VERIFIER) << "cflowInfo is nullptr ";
141         return {};
142     }
143     if (cflowInfo->FillCodeMaps(method) == VerificationStatus::ERROR) {
144         return {};
145     }
146 
147     // 2. Mark exception handlers.
148     if (cflowInfo->ProcessCatchBlocks(method) == VerificationStatus::ERROR) {
149         return {};
150     }
151 
152     return cflowInfo;
153 }
154 
155 }  // namespace ark::verifier
156