From 2e4e13c777c7ed44dbb5fba43e22470492b67646 Mon Sep 17 00:00:00 2001 From: Marat Dinmukhametov Date: Mon, 13 Mar 2023 17:34:36 +0300 Subject: [PATCH 1/2] [Verifier] Separation of the verifier Executable file to the executable and the independent library Signed-off-by: Marat Dinmukhametov --- verification/verifier/CMakeLists.txt | 29 ++- verification/verifier/verifier.cpp | 339 ++----------------------- verification/verifier/verifier_lib.cpp | 334 ++++++++++++++++++++++++ verification/verifier/verifier_lib.h | 52 ++++ 4 files changed, 422 insertions(+), 332 deletions(-) create mode 100644 verification/verifier/verifier_lib.cpp create mode 100644 verification/verifier/verifier_lib.h diff --git a/verification/verifier/CMakeLists.txt b/verification/verifier/CMakeLists.txt index 8d379f8c0..2a63719e9 100644 --- a/verification/verifier/CMakeLists.txt +++ b/verification/verifier/CMakeLists.txt @@ -19,15 +19,28 @@ set(SOURCES verifier.cpp) panda_add_executable(verifier ${SOURCES}) -target_include_directories(verifier PUBLIC ${PANDA_ROOT}/libpandabase/ - ${PANDA_ROOT}/runtime/ - ${PANDA_BINARY_ROOT} - ${VERIFIER_INCLUDE_DIR} -) +add_library(verifier_obj OBJECT verifier_lib.cpp) -target_link_libraries(verifier arkruntime arkbase) +target_link_libraries(verifier_obj arkruntime arkbase) + +set_target_properties(verifier_obj PROPERTIES + POSITION_INDEPENDENT_CODE ON + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN ON + ) + +target_include_directories(verifier_obj PUBLIC + ${PANDA_ROOT}/libpandabase/ + ${PANDA_ROOT}/runtime/ + ${PANDA_BINARY_ROOT} + ${VERIFIER_INCLUDE_DIR} + ) + +panda_add_sanitizers(TARGET verifier_obj SANITIZERS ${PANDA_SANITIZERS_LIST}) panda_add_sanitizers(TARGET verifier SANITIZERS ${PANDA_SANITIZERS_LIST}) -panda_gen_options(TARGET verifier YAML_FILE options.yaml GENERATED_HEADER - verifier_options_gen.h) +panda_gen_options(TARGET verifier_obj YAML_FILE options.yaml GENERATED_HEADER + verifier_options_gen.h) + +target_link_libraries(verifier verifier_obj) diff --git a/verification/verifier/verifier.cpp b/verification/verifier/verifier.cpp index a1be74c8a..75bf18265 100644 --- a/verification/verifier/verifier.cpp +++ b/verification/verifier/verifier.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2023 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 @@ -13,251 +13,13 @@ * limitations under the License. */ -#include "libpandabase/os/native_stack.h" -#include "monitor.h" -#include "os/mutex.h" -#include "runtime/include/runtime.h" -#include "runtime/include/thread_scopes.h" -#include "utils/logger.h" +#include "verifier_lib.h" + #include "utils/span.h" -#include "verification/plugins.h" -#include "verification/util/is_system.h" -#include "verification/util/optional_ref.h" #include "generated/base_options.h" - -// generated #include "ark_version.h" -#include "generated/verifier_options_gen.h" - -#include -#include -#include - -namespace panda::verifier { - -size_t const MAX_THREADS = 64; - -void Worker(PandaDeque *queue, os::memory::Mutex *lock, size_t thread_num, std::atomic *result) -{ - LOG(DEBUG, VERIFIER) << "Verifier thread " << thread_num << " starting"; - { - std::stringstream ss; - ss << "Verifier #" << thread_num; - if (os::thread::SetThreadName(os::thread::GetNativeHandle(), ss.str().c_str()) != 0) { - LOG(ERROR, VERIFIER) << "Failed to set worker thread name " << ss.str(); - } - } - - auto *service = Runtime::GetCurrent()->GetVerifierService(); - - ManagedThread *thread = nullptr; - panda_file::SourceLang current_lang = panda_file::SourceLang::INVALID; - for (;;) { - Method *method; - { - os::memory::LockHolder lh {*lock}; - if (queue->empty()) { - break; - } - method = queue->front(); - queue->pop_front(); - } - auto method_lang = method->GetClass()->GetSourceLang(); - if (method_lang != current_lang) { - if (thread != nullptr) { - plugin::GetLanguagePlugin(current_lang)->DestroyManagedThread(thread); - } - thread = plugin::GetLanguagePlugin(method_lang)->CreateManagedThread(); - current_lang = method_lang; - } - if (panda::verifier::Verify(service, method) != Status::OK) { - *result = false; - LOG(ERROR, VERIFIER) << "Error: method " << method->GetFullName(true) << " failed to verify"; - } - } - if (thread != nullptr) { - plugin::GetLanguagePlugin(current_lang)->DestroyManagedThread(thread); - } - LOG(DEBUG, VERIFIER) << "Verifier thread " << thread_num << " finishing"; -} - -bool RunVerifier(const Options &cli_options) -{ - auto is_perf_measure = cli_options.IsPerfMeasure(); - std::chrono::steady_clock::time_point begin; - std::chrono::steady_clock::time_point end; - - PandaDeque queue; - os::memory::Mutex lock; - - auto &runtime = *Runtime::GetCurrent(); - auto &class_linker = *runtime.GetClassLinker(); - - const std::vector &class_names = cli_options.GetClasses(); - const std::vector &method_names = cli_options.GetMethods(); - - std::atomic result = true; - - PandaUnorderedSet methods_set; - - auto enqueue_method = [&](Method *method) { - if (methods_set.count(method) == 0) { - queue.push_back(method); - methods_set.insert(method); - } - }; - - bool verify_libraries = runtime.GetOptions().IsVerifyRuntimeLibraries(); - - auto enqueue_class = [&](const Class &klass) { - // this is already checked in enqueue_method, but faster to skip them in the first place - if (!verify_libraries && IsSystemClass(klass)) { - LOG(INFO, VERIFIER) << klass.GetName() << " is a system class, skipping"; - return; - } - LOG(INFO, VERIFIER) << "Begin verification of class " << klass.GetName(); - for (auto &method : klass.GetMethods()) { - enqueue_method(&method); - } - }; - - // we need ScopedManagedCodeThread for the verifier since it can allocate objects - { - ScopedManagedCodeThread managed_obj_thread(ManagedThread::GetCurrent()); - if (class_names.empty() && method_names.empty()) { - auto handle_file = [&](const panda_file::File &file) { - LOG(INFO, VERIFIER) << "Processing file" << file.GetFilename(); - for (auto id : file.GetClasses()) { - panda_file::File::EntityId entity_id {id}; - if (!file.IsExternal(entity_id)) { - auto opt_lang = panda_file::ClassDataAccessor {file, entity_id}.GetSourceLang(); - ClassLinkerExtension *ext = - class_linker.GetExtension(opt_lang.value_or(panda_file::SourceLang::PANDA_ASSEMBLY)); - if (ext == nullptr) { - LOG(ERROR, VERIFIER) << "Error: Class Linker Extension failed to initialize"; - return false; - } - const Class *klass = ext->GetClass(file, entity_id); - - if (klass != nullptr) { - enqueue_class(*klass); - } - } - } - return true; - }; - - class_linker.EnumeratePandaFiles(handle_file); - - if (verify_libraries) { - class_linker.EnumerateBootPandaFiles(handle_file); - } else if (runtime.GetPandaFiles().empty()) { - // in this case the last boot-panda-file and only it is actually not a system file and should be - // verified - OptionalConstRef file; - class_linker.EnumerateBootPandaFiles([&file](const panda_file::File &pf) { - file = std::cref(pf); - return true; - }); - if (file.HasRef()) { - handle_file(*file); - } else { - LOG(ERROR, VERIFIER) << "No files given to verify"; - } - } - } else { - PandaUnorderedMap classes_by_name; - ClassLinkerContext *ctx = - class_linker.GetExtension(runtime.GetLanguageContext(runtime.GetRuntimeType()))->GetBootContext(); - - auto get_class_by_name = [&](const std::string &class_name) -> Class * { - auto it = classes_by_name.find(class_name); - if (it != classes_by_name.end()) { - return it->second; - } - - PandaString descriptor; - const uint8_t *class_name_bytes = - ClassHelper::GetDescriptor(utf::CStringAsMutf8(class_name.c_str()), &descriptor); - Class *klass = class_linker.GetClass(class_name_bytes, true, ctx); - if (klass == nullptr) { - LOG(ERROR, VERIFIER) << "Error: Cannot resolve class with name " << class_name; - result = false; - } - - classes_by_name.emplace(class_name, klass); - return klass; - }; - - for (const auto &class_name : class_names) { - Class *klass = get_class_by_name(class_name); - // the bad case is already handled in get_class_by_name - if (klass != nullptr) { - enqueue_class(*klass); - } - } - for (const std::string &fq_method_name : method_names) { - size_t pos = fq_method_name.find_last_of("::"); - if (pos == std::string::npos) { - LOG(ERROR, VERIFIER) << "Error: Fully qualified method name must contain '::', was " - << fq_method_name; - result = false; - break; - } - std::string class_name = fq_method_name.substr(0, pos - 1); - std::string_view unqualified_method_name = std::string_view(fq_method_name).substr(pos + 1); - if (std::find(class_names.begin(), class_names.end(), class_name) != class_names.end()) { - // this method was already verified while enumerating class_names - continue; - } - Class *klass = get_class_by_name(class_name); - if (klass != nullptr) { - bool method_found = false; - for (auto &method : klass->GetMethods()) { - const char *name_data = utf::Mutf8AsCString(method.GetName().data); - if (std::string_view(name_data) == unqualified_method_name) { - method_found = true; - LOG(INFO, VERIFIER) << "Verification of method '" << fq_method_name << "'"; - enqueue_method(&method); - } - } - if (!method_found) { - LOG(ERROR, VERIFIER) << "Error: Cannot resolve method with name " << unqualified_method_name - << " in class " << class_name; - result = false; - } - } - } - } - } - - if (is_perf_measure) { - begin = std::chrono::steady_clock::now(); - } - - size_t nthreads = runtime.GetOptions().GetVerificationThreads(); - std::vector threads; - for (size_t i = 0; i < nthreads; i++) { - auto *worker = runtime.GetInternalAllocator()->New(Worker, &queue, &lock, i, &result); - threads.push_back(worker); - } - - for (auto *thr : threads) { - thr->join(); - runtime.GetInternalAllocator()->Delete(thr); - } - - if (is_perf_measure) { - end = std::chrono::steady_clock::now(); - std::cout << "Verification time = " - << std::chrono::duration_cast(end - begin).count() << " us" << std::endl; - } - - return result; -} - -void PrintHelp(const PandArgParser &pa_parser) +void PrintHelp(const panda::PandArgParser &pa_parser) { std::string error = pa_parser.GetErrorString(); if (!error.empty()) { @@ -269,18 +31,16 @@ void PrintHelp(const PandArgParser &pa_parser) << pa_parser.GetHelpString() << std::endl; } -int Main(int argc, const char **argv) +int main(int argc, const char **argv) { - Span sp(argv, argc); - RuntimeOptions runtime_options(sp[0]); - Options cli_options(sp[0]); - PandArgParser pa_parser; - base_options::Options base_options(""); + panda::Span sp(argv, argc); + panda::verifier::Options cli_options(sp[0]); + panda::PandArgParser pa_parser; - PandArg help("help", false, "Print this message and exit"); - PandArg options("options", false, "Print verifier options"); + panda::PandArg help("help", false, "Print this message and exit"); + panda::PandArg options("options", false, "Print verifier options"); // tail argument - PandArg file("file", "", "path to pandafile"); + panda::PandArg file("file", "", "path to pandafile"); cli_options.AddOptions(&pa_parser); @@ -294,8 +54,8 @@ int Main(int argc, const char **argv) return 1; } - if (runtime_options.IsVersion()) { - PrintPandaVersion(); + if (cli_options.IsVersion()) { + panda::PrintPandaVersion(); return 0; } @@ -315,75 +75,6 @@ int Main(int argc, const char **argv) return 1; } - auto boot_panda_files = cli_options.GetBootPandaFiles(); - auto panda_files = cli_options.GetPandaFiles(); - std::string main_file_name = file.GetValue(); - - if (!main_file_name.empty()) { - if (panda_files.empty()) { - boot_panda_files.push_back(main_file_name); - } else { - auto found_iter = std::find_if(panda_files.begin(), panda_files.end(), - [&](auto &file_name) { return main_file_name == file_name; }); - if (found_iter == panda_files.end()) { - panda_files.push_back(main_file_name); - } - } - } - - runtime_options.SetBootPandaFiles(boot_panda_files); - runtime_options.SetPandaFiles(panda_files); - runtime_options.SetLoadRuntimes(cli_options.GetLoadRuntimes()); - runtime_options.SetGcType(cli_options.GetGcType()); - - base_options.SetLogComponents(cli_options.GetLogComponents()); - base_options.SetLogLevel(cli_options.GetLogLevel()); - base_options.SetLogStream(cli_options.GetLogStream()); - base_options.SetLogFile(cli_options.GetLogFile()); - Logger::Initialize(base_options); - - runtime_options.SetLimitStandardAlloc(cli_options.IsLimitStandardAlloc()); - runtime_options.SetInternalAllocatorType(cli_options.GetInternalAllocatorType()); - runtime_options.SetInternalMemorySizeLimit(cli_options.GetInternalMemorySizeLimit()); - - runtime_options.SetVerificationMode(cli_options.IsDebugMode() ? VerificationMode::DEBUG - : VerificationMode::AHEAD_OF_TIME); - runtime_options.SetVerificationConfigFile(cli_options.GetConfigFile()); - runtime_options.SetVerificationCacheFile(cli_options.GetCacheFile()); - runtime_options.SetVerificationUpdateCache(cli_options.IsUpdateCache()); - runtime_options.SetVerifyRuntimeLibraries(cli_options.IsVerifyRuntimeLibraries()); - uint32_t threads = cli_options.GetThreads(); - if (threads == 0) { - threads = std::thread::hardware_concurrency(); - // hardware_concurrency can return 0 if the value is not computable or well defined - if (threads == 0) { - threads = 1; - } else if (threads > MAX_THREADS) { - threads = MAX_THREADS; - } - } - runtime_options.SetVerificationThreads(threads); - - if (!Runtime::Create(runtime_options)) { - std::cerr << "Error: cannot create runtime" << std::endl; - return -1; - } - - int ret = RunVerifier(cli_options) ? 0 : -1; - - if (cli_options.IsPrintMemoryStatistics()) { - std::cout << Runtime::GetCurrent()->GetMemoryStatistics(); - } - if (!Runtime::Destroy()) { - std::cerr << "Error: cannot destroy runtime" << std::endl; - return -1; - } - return ret; -} - -} // namespace panda::verifier - -int main(int argc, const char **argv) -{ - return panda::verifier::Main(argc, argv); + panda::verifier::Verifier verifier(sp[0], cli_options, file.GetValue()); + return verifier.RunVerifier() ? 0 : -1; } diff --git a/verification/verifier/verifier_lib.cpp b/verification/verifier/verifier_lib.cpp new file mode 100644 index 000000000..08f4bee57 --- /dev/null +++ b/verification/verifier/verifier_lib.cpp @@ -0,0 +1,334 @@ +/** +* Copyright (c) 2021-2023 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 "verifier_lib.h" + +#include "os/mutex.h" +#include "runtime/include/runtime.h" +#include "runtime/include/thread_scopes.h" +#include "utils/logger.h" +#include "utils/span.h" +#include "verification/plugins.h" +#include "verification/util/is_system.h" +#include "verification/util/optional_ref.h" +#include "ark_version.h" +#include +#include +#include + +// generated +#include "generated/base_options.h" + +namespace panda::verifier { + +Verifier::Verifier(std::string exe_path, Options &cli_options, std::string main_file_name) + : exe_path(std::move(exe_path)), cli_options_(cli_options), runtime_options_(panda::RuntimeOptions(exe_path)) +{ + PrepareRuntimeOptions(cli_options_, runtime_options_, std::move(main_file_name)); + + if (!Runtime::Create(runtime_options_)) { + std::cerr << "Error: cannot create runtime" << std::endl; + exit(-1); + } +} + +bool Verifier::RunVerifier() +{ + auto is_perf_measure = cli_options_.IsPerfMeasure(); + std::chrono::steady_clock::time_point begin; + std::chrono::steady_clock::time_point end; + + PandaDeque queue; + os::memory::Mutex lock; + + auto &runtime = *Runtime::GetCurrent(); + auto &class_linker = *runtime.GetClassLinker(); + + const std::vector &class_names = cli_options_.GetClasses(); + const std::vector &method_names = cli_options_.GetMethods(); + + std::atomic result = true; + + PandaUnorderedSet methods_set; + + auto enqueue_method = [&](Method *method) { + if (methods_set.count(method) == 0) { + queue.push_back(method); + methods_set.insert(method); + } + }; + + bool verify_libraries = runtime.GetOptions().IsVerifyRuntimeLibraries(); + + auto enqueue_class = [&](const Class &klass) { + // this is already checked in enqueue_method, but faster to skip them in the first place + if (!verify_libraries && IsSystemClass(klass)) { + LOG(INFO, VERIFIER) << klass.GetName() << " is a system class, skipping"; + return; + } + LOG(INFO, VERIFIER) << "Begin verification of class " << klass.GetName(); + for (auto &method : klass.GetMethods()) { + enqueue_method(&method); + } + }; + + // we need ScopedManagedCodeThread for the verifier since it can allocate objects + { + ScopedManagedCodeThread managed_obj_thread(ManagedThread::GetCurrent()); + if (class_names.empty() && method_names.empty()) { + auto handle_file = [&](const panda_file::File &file) { + LOG(INFO, VERIFIER) << "Processing file" << file.GetFilename(); + for (auto id : file.GetClasses()) { + panda_file::File::EntityId entity_id {id}; + if (!file.IsExternal(entity_id)) { + auto opt_lang = panda_file::ClassDataAccessor {file, entity_id}.GetSourceLang(); + ClassLinkerExtension *ext = + class_linker.GetExtension(opt_lang.value_or(panda_file::SourceLang::PANDA_ASSEMBLY)); + if (ext == nullptr) { + LOG(ERROR, VERIFIER) << "Error: Class Linker Extension failed to initialize"; + return false; + } + const Class *klass = ext->GetClass(file, entity_id); + + if (klass != nullptr) { + enqueue_class(*klass); + } + } + } + return true; + }; + + class_linker.EnumeratePandaFiles(handle_file); + + if (verify_libraries) { + class_linker.EnumerateBootPandaFiles(handle_file); + } else if (runtime.GetPandaFiles().empty()) { + // in this case the last boot-panda-file and only it is actually not a system file and should be + // verified + OptionalConstRef file; + class_linker.EnumerateBootPandaFiles([&file](const panda_file::File &pf) { + file = std::cref(pf); + return true; + }); + if (file.HasRef()) { + handle_file(*file); + } else { + LOG(ERROR, VERIFIER) << "No files given to verify"; + } + } + } else { + PandaUnorderedMap classes_by_name; + ClassLinkerContext *ctx = + class_linker.GetExtension(runtime.GetLanguageContext(runtime.GetRuntimeType()))->GetBootContext(); + + auto get_class_by_name = [&](const std::string &class_name) -> Class * { + auto it = classes_by_name.find(class_name); + if (it != classes_by_name.end()) { + return it->second; + } + + PandaString descriptor; + const uint8_t *class_name_bytes = + ClassHelper::GetDescriptor(utf::CStringAsMutf8(class_name.c_str()), &descriptor); + Class *klass = class_linker.GetClass(class_name_bytes, true, ctx); + if (klass == nullptr) { + LOG(ERROR, VERIFIER) << "Error: Cannot resolve class with name " << class_name; + result = false; + } + + classes_by_name.emplace(class_name, klass); + return klass; + }; + + for (const auto &class_name : class_names) { + Class *klass = get_class_by_name(class_name); + // the bad case is already handled in get_class_by_name + if (klass != nullptr) { + enqueue_class(*klass); + } + } + + for (const std::string &fq_method_name : method_names) { + size_t pos = fq_method_name.find_last_of("::"); + if (pos == std::string::npos) { + LOG(ERROR, VERIFIER) << "Error: Fully qualified method name must contain '::', was " + << fq_method_name; + result = false; + break; + } + std::string class_name = fq_method_name.substr(0, pos - 1); + std::string_view unqualified_method_name = std::string_view(fq_method_name).substr(pos + 1); + if (std::find(class_names.begin(), class_names.end(), class_name) != class_names.end()) { + // this method was already verified while enumerating class_names + continue; + } + Class *klass = get_class_by_name(class_name); + if (klass != nullptr) { + bool method_found = false; + for (auto &method : klass->GetMethods()) { + const char *name_data = utf::Mutf8AsCString(method.GetName().data); + if (std::string_view(name_data) == unqualified_method_name) { + method_found = true; + LOG(INFO, VERIFIER) << "Verification of method '" << fq_method_name << "'"; + enqueue_method(&method); + } + } + if (!method_found) { + LOG(ERROR, VERIFIER) << "Error: Cannot resolve method with name " << unqualified_method_name + << " in class " << class_name; + result = false; + } + } + } + } + } + + if (is_perf_measure) { + begin = std::chrono::steady_clock::now(); + } + + size_t nthreads = runtime.GetOptions().GetVerificationThreads(); + std::vector threads; + for (size_t i = 0; i < nthreads; i++) { + auto *worker = runtime.GetInternalAllocator()->New(Worker, &queue, &lock, i, &result); + threads.push_back(worker); + } + + for (auto *thr : threads) { + thr->join(); + runtime.GetInternalAllocator()->Delete(thr); + } + + if (is_perf_measure) { + end = std::chrono::steady_clock::now(); + std::cout << "Verification time = " + << std::chrono::duration_cast(end - begin).count() << " us" << std::endl; + } + + if (cli_options_.IsPrintMemoryStatistics()) { + std::cout << Runtime::GetCurrent()->GetMemoryStatistics(); + } + + return result; +} + +void Verifier::PrepareRuntimeOptions(const Options &cli_options, RuntimeOptions &runtime_options, + std::string main_file_name) +{ + base_options::Options base_options(""); + + auto boot_panda_files = cli_options.GetBootPandaFiles(); + auto panda_files = cli_options.GetPandaFiles(); + + if (!main_file_name.empty()) { + if (panda_files.empty()) { + boot_panda_files.push_back(main_file_name); + } else { + auto found_iter = std::find_if(panda_files.begin(), panda_files.end(), + [&](auto &file_name) { return main_file_name == file_name; }); + if (found_iter == panda_files.end()) { + panda_files.push_back(main_file_name); + } + } + } + + runtime_options.SetBootPandaFiles(boot_panda_files); + runtime_options.SetPandaFiles(panda_files); + runtime_options.SetLoadRuntimes(cli_options.GetLoadRuntimes()); + runtime_options.SetGcType(cli_options.GetGcType()); + + base_options.SetLogComponents(cli_options.GetLogComponents()); + base_options.SetLogLevel(cli_options.GetLogLevel()); + base_options.SetLogStream(cli_options.GetLogStream()); + base_options.SetLogFile(cli_options.GetLogFile()); + Logger::Initialize(base_options); + + runtime_options.SetLimitStandardAlloc(cli_options.IsLimitStandardAlloc()); + runtime_options.SetInternalAllocatorType(cli_options.GetInternalAllocatorType()); + runtime_options.SetInternalMemorySizeLimit(cli_options.GetInternalMemorySizeLimit()); + + runtime_options.SetVerificationMode(cli_options.IsDebugMode() ? VerificationMode::DEBUG + : VerificationMode::AHEAD_OF_TIME); + runtime_options.SetVerificationConfigFile(cli_options.GetConfigFile()); + runtime_options.SetVerificationCacheFile(cli_options.GetCacheFile()); + runtime_options.SetVerificationUpdateCache(cli_options.IsUpdateCache()); + runtime_options.SetVerifyRuntimeLibraries(cli_options.IsVerifyRuntimeLibraries()); + uint32_t threads = cli_options.GetThreads(); + if (threads == 0) { + threads = std::thread::hardware_concurrency(); + // hardware_concurrency can return 0 if the value is not computable or well defined + if (threads == 0) { + threads = 1; + } else if (threads > MAX_THREADS) { + threads = MAX_THREADS; + } + } + runtime_options.SetVerificationThreads(threads); +} + +void Verifier::Worker(PandaDeque *queue, os::memory::Mutex *lock, size_t thread_num, + std::atomic *result) +{ + LOG(DEBUG, VERIFIER) << "Verifier thread " << thread_num << " starting"; + { + std::stringstream ss; + ss << "Verifier #" << thread_num; + if (os::thread::SetThreadName(os::thread::GetNativeHandle(), ss.str().c_str()) != 0) { + LOG(ERROR, VERIFIER) << "Failed to set worker thread name " << ss.str(); + } + } + + auto *service = Runtime::GetCurrent()->GetVerifierService(); + + ManagedThread *thread = nullptr; + panda_file::SourceLang current_lang = panda_file::SourceLang::INVALID; + for (;;) { + Method *method; + { + os::memory::LockHolder lh {*lock}; + if (queue->empty()) { + break; + } + method = queue->front(); + queue->pop_front(); + } + auto method_lang = method->GetClass()->GetSourceLang(); + if (method_lang != current_lang) { + if (thread != nullptr) { + plugin::GetLanguagePlugin(current_lang)->DestroyManagedThread(thread); + } + thread = plugin::GetLanguagePlugin(method_lang)->CreateManagedThread(); + current_lang = method_lang; + } + if (panda::verifier::Verify(service, method) != Status::OK) { + *result = false; + LOG(ERROR, VERIFIER) << "Error: method " << method->GetFullName(true) << " failed to verify"; + } + } + if (thread != nullptr) { + plugin::GetLanguagePlugin(current_lang)->DestroyManagedThread(thread); + } + LOG(DEBUG, VERIFIER) << "Verifier thread " << thread_num << " finishing"; +} + +Verifier::~Verifier() +{ + if (!Runtime::Destroy()) { + std::cerr << "Error: cannot destroy runtime" << std::endl; + exit(-1); + } +} + +} // namespace panda::verifier diff --git a/verification/verifier/verifier_lib.h b/verification/verifier/verifier_lib.h new file mode 100644 index 000000000..25f4d59fa --- /dev/null +++ b/verification/verifier/verifier_lib.h @@ -0,0 +1,52 @@ +/** +* Copyright (c) 2021-2023 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. +*/ + +#ifndef PANDA_VERIFIER_LIB_H +#define PANDA_VERIFIER_LIB_H + +#include "utils/pandargs.h" +#include "include/method.h" +#include "include/runtime_options.h" + +// generated +#include "generated/verifier_options_gen.h" + +namespace panda::verifier { + +class Verifier { +public: + Verifier(std::string exe_path, verifier::Options &cli_options, std::string main_file_name); + + bool RunVerifier(); + + ~Verifier(); + +private: + const std::string exe_path; + verifier::Options cli_options_; + panda::RuntimeOptions runtime_options_; + + static size_t const MAX_THREADS = 64; + + static void PrepareRuntimeOptions(const Options &cli_options, panda::RuntimeOptions &runtime_options, + std::string main_file_name); + + static void Worker(PandaDeque *queue, os::memory::Mutex *lock, size_t thread_num, + std::atomic *result); +}; + +} // namespace panda::verifier + +#endif // PANDA_VERIFIER_LIB_H -- Gitee From b8bf5ac5d0bd7644232c9ea45ca226651d9c0f2f Mon Sep 17 00:00:00 2001 From: Marat Dinmukhametov Date: Thu, 16 Mar 2023 22:10:48 +0300 Subject: [PATCH 2/2] [Verifier] Fix name shadowing Signed-off-by: Marat Dinmukhametov --- verification/verifier/verifier_lib.cpp | 30 +++++++++++++------------- verification/verifier/verifier_lib.h | 29 ++++++++++++------------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/verification/verifier/verifier_lib.cpp b/verification/verifier/verifier_lib.cpp index 08f4bee57..db2792c45 100644 --- a/verification/verifier/verifier_lib.cpp +++ b/verification/verifier/verifier_lib.cpp @@ -1,17 +1,17 @@ /** -* Copyright (c) 2021-2023 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. -*/ + * Copyright (c) 2021-2023 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 "verifier_lib.h" @@ -33,8 +33,8 @@ namespace panda::verifier { -Verifier::Verifier(std::string exe_path, Options &cli_options, std::string main_file_name) - : exe_path(std::move(exe_path)), cli_options_(cli_options), runtime_options_(panda::RuntimeOptions(exe_path)) +Verifier::Verifier(const std::string &exe_path, Options &cli_options, std::string main_file_name) + : cli_options_(cli_options), runtime_options_(panda::RuntimeOptions(exe_path)) { PrepareRuntimeOptions(cli_options_, runtime_options_, std::move(main_file_name)); diff --git a/verification/verifier/verifier_lib.h b/verification/verifier/verifier_lib.h index 25f4d59fa..34843755b 100644 --- a/verification/verifier/verifier_lib.h +++ b/verification/verifier/verifier_lib.h @@ -1,17 +1,17 @@ /** -* Copyright (c) 2021-2023 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. -*/ + * Copyright (c) 2021-2023 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. + */ #ifndef PANDA_VERIFIER_LIB_H #define PANDA_VERIFIER_LIB_H @@ -27,14 +27,13 @@ namespace panda::verifier { class Verifier { public: - Verifier(std::string exe_path, verifier::Options &cli_options, std::string main_file_name); + Verifier(const std::string &exe_path, Options &cli_options, std::string main_file_name); bool RunVerifier(); ~Verifier(); private: - const std::string exe_path; verifier::Options cli_options_; panda::RuntimeOptions runtime_options_; -- Gitee