1 /**
2 * Copyright (c) 2021-2024 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 "public.h"
17 #include "public_internal.h"
18 #include "runtime/include/mem/allocator.h"
19 #include "verification/config/config_load.h"
20 #include "verification/config/context/context.h"
21 #include "verification/cache/results_cache.h"
22 #include "verification/jobs/service.h"
23 #include "verification/jobs/job.h"
24
25 namespace ark::verifier {
26
NewConfig()27 Config *NewConfig()
28 {
29 auto result = new Config;
30 result->opts.Initialize();
31 return result;
32 }
33
LoadConfigFile(Config * config,std::string_view configFileName)34 bool LoadConfigFile(Config *config, std::string_view configFileName)
35 {
36 return ark::verifier::config::LoadConfig(config, configFileName);
37 }
38
DestroyConfig(Config * config)39 void DestroyConfig(Config *config)
40 {
41 config->opts.Destroy();
42 delete config;
43 }
44
IsEnabled(Config const * config)45 bool IsEnabled(Config const *config)
46 {
47 ASSERT(config != nullptr);
48 return config->opts.IsEnabled();
49 }
50
IsOnlyVerify(Config const * config)51 bool IsOnlyVerify(Config const *config)
52 {
53 ASSERT(config != nullptr);
54 return config->opts.IsOnlyVerify();
55 }
56
CreateService(Config const * config,ark::mem::InternalAllocatorPtr allocator,ClassLinker * linker,std::string const & cacheFileName)57 Service *CreateService(Config const *config, ark::mem::InternalAllocatorPtr allocator, ClassLinker *linker,
58 std::string const &cacheFileName)
59 {
60 if (!cacheFileName.empty()) {
61 VerificationResultCache::Initialize(cacheFileName);
62 }
63 auto res = allocator->New<Service>();
64 res->config = config;
65 res->classLinker = linker;
66 res->allocator = allocator;
67 res->verifierService = allocator->New<VerifierService>(allocator, linker);
68 res->verifierService->Init();
69 res->debugCtx.SetConfig(&config->debugCfg);
70 return res;
71 }
72
DestroyService(Service * service,bool updateCacheFile)73 void DestroyService(Service *service, bool updateCacheFile)
74 {
75 if (service == nullptr) {
76 return;
77 }
78 VerificationResultCache::Destroy(updateCacheFile);
79 auto allocator = service->allocator;
80 service->verifierService->Destroy();
81 allocator->Delete(service->verifierService);
82 allocator->Delete(service);
83 }
84
GetServiceConfig(Service const * service)85 Config const *GetServiceConfig(Service const *service)
86 {
87 return service->config;
88 }
89
90 // Do we really need this public/private distinction here?
ToPublic(VerificationResultCache::Status status)91 inline Status ToPublic(VerificationResultCache::Status status)
92 {
93 switch (status) {
94 case VerificationResultCache::Status::OK:
95 return Status::OK;
96 case VerificationResultCache::Status::FAILED:
97 return Status::FAILED;
98 case VerificationResultCache::Status::UNKNOWN:
99 return Status::UNKNOWN;
100 default:
101 UNREACHABLE();
102 }
103 }
104
ReportStatus(Service const * service,Method const * method,std::string const & status)105 static void ReportStatus(Service const *service, Method const *method, std::string const &status)
106 {
107 if (service->config->opts.show.status) {
108 LOG(DEBUG, VERIFIER) << "Verification result for method " << method->GetFullName(true) << ": " << status;
109 }
110 }
111
VerifyClass(Class * clazz)112 static bool VerifyClass(Class *clazz)
113 {
114 auto *langPlugin = plugin::GetLanguagePlugin(clazz->GetSourceLang());
115 auto result = langPlugin->CheckClass(clazz);
116 if (!result.IsOk()) {
117 LOG(ERROR, VERIFIER) << result.msg << " " << clazz->GetName();
118 clazz->SetState(Class::State::ERRONEOUS);
119 return false;
120 }
121
122 Class *parent = clazz->GetBase();
123 if (parent != nullptr && parent->IsFinal()) {
124 LOG(ERROR, VERIFIER) << "Cannot inherit from final class: " << clazz->GetName() << "->" << parent->GetName();
125 clazz->SetState(Class::State::ERRONEOUS);
126 return false;
127 }
128
129 clazz->SetState(Class::State::VERIFIED);
130 return true;
131 }
132
CheckBeforeVerification(Service * service,ark::Method * method,VerificationMode mode)133 static std::optional<Status> CheckBeforeVerification(Service *service, ark::Method *method, VerificationMode mode)
134 {
135 using VStage = Method::VerificationStage;
136 if (method->IsIntrinsic()) {
137 return Status::OK;
138 }
139
140 /*
141 * Races are possible where the same method gets simultaneously verified on different threads.
142 * But those are harmless, so we ignore them.
143 */
144 auto stage = method->GetVerificationStage();
145 if (stage == VStage::VERIFIED_OK) {
146 return Status::OK;
147 }
148 if (stage == VStage::VERIFIED_FAIL) {
149 return Status::FAILED;
150 }
151
152 if (!IsEnabled(mode)) {
153 ReportStatus(service, method, "SKIP");
154 return Status::OK;
155 }
156 if (method->GetInstructions() == nullptr) {
157 LOG(DEBUG, VERIFIER) << method->GetFullName(true) << " has no code, no meaningful verification";
158 return Status::OK;
159 }
160 service->debugCtx.AddMethod(*method, mode == VerificationMode::DEBUG);
161 if (service->debugCtx.SkipVerification(method->GetUniqId())) {
162 LOG(DEBUG, VERIFIER) << "Skipping verification of '" << method->GetFullName()
163 << "' according to verifier configuration";
164 return Status::OK;
165 }
166
167 auto uniqId = method->GetUniqId();
168 auto methodName = method->GetFullName();
169 if (VerificationResultCache::Enabled()) {
170 auto cachedStatus = ToPublic(VerificationResultCache::Check(uniqId));
171 if (cachedStatus != Status::UNKNOWN) {
172 LOG(DEBUG, VERIFIER) << "Verification result of method '" << methodName
173 << "' was cached: " << (cachedStatus == Status::OK ? "OK" : "FAIL");
174 return cachedStatus;
175 }
176 }
177
178 return std::nullopt;
179 }
180
Verify(Service * service,ark::Method * method,VerificationMode mode)181 Status Verify(Service *service, ark::Method *method, VerificationMode mode)
182 {
183 using VStage = Method::VerificationStage;
184 ASSERT(service != nullptr);
185
186 auto status = CheckBeforeVerification(service, method, mode);
187 if (status) {
188 return status.value();
189 }
190
191 auto uniqId = method->GetUniqId();
192 auto methodName = method->GetFullName();
193
194 auto lang = method->GetClass()->GetSourceLang();
195 auto *processor = service->verifierService->GetProcessor(lang);
196
197 if (processor == nullptr) {
198 LOG(INFO, VERIFIER) << "Attempt to verify " << method->GetFullName(true)
199 << "after service started shutdown, ignoring";
200 return Status::FAILED;
201 }
202
203 auto const &methodOptions = service->config->opts.debug.GetMethodOptions();
204 auto const &verifMethodOptions = methodOptions[methodName];
205 LOG(DEBUG, VERIFIER) << "Verification config for '" << methodName << "': " << verifMethodOptions.GetName();
206 LOG(INFO, VERIFIER) << "Started verification of method '" << method->GetFullName(true) << "'";
207
208 // class verification can be called concurrently
209 if ((method->GetClass()->GetState() < Class::State::VERIFIED) && !VerifyClass(method->GetClass())) {
210 return Status::FAILED;
211 }
212 Job job {service, method, verifMethodOptions};
213 bool result = job.DoChecks(processor->GetTypeSystem());
214
215 LOG(DEBUG, VERIFIER) << "Verification result for '" << methodName << "': " << result;
216
217 service->verifierService->ReleaseProcessor(processor);
218
219 VerificationResultCache::CacheResult(uniqId, result);
220
221 if (result) {
222 method->SetVerificationStage(VStage::VERIFIED_OK);
223 ReportStatus(service, method, "OK");
224 return Status::OK;
225 }
226 method->SetVerificationStage(VStage::VERIFIED_FAIL);
227 ReportStatus(service, method, "FAIL");
228 return Status::FAILED;
229 }
230
231 } // namespace ark::verifier
232