From df5fd8bb978793d319ba76d8b092dc4a75ec7b9e Mon Sep 17 00:00:00 2001 From: "Zhao, Yang2" Date: Sun, 21 Jul 2024 22:36:23 -0700 Subject: [PATCH 01/12] fix destruction --- .../layers/sanitizer/asan_interceptor.cpp | 4 ++ .../layers/sanitizer/asan_interceptor.hpp | 8 +++ source/loader/layers/sanitizer/ur_sanddi.cpp | 69 +++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/source/loader/layers/sanitizer/asan_interceptor.cpp b/source/loader/layers/sanitizer/asan_interceptor.cpp index fc0b312e5f..98a9422a32 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.cpp +++ b/source/loader/layers/sanitizer/asan_interceptor.cpp @@ -158,6 +158,10 @@ SanitizerInterceptor::SanitizerInterceptor(logger::Logger &logger) SanitizerInterceptor::~SanitizerInterceptor() { DestroyShadowMemoryOnCPU(); DestroyShadowMemoryOnPVC(); + + for (auto Adapter : m_Adapters) { + getContext()->urDdiTable.Global.pfnAdapterRelease(Adapter); + } } /// The memory chunk allocated from the underlying allocator looks like this: diff --git a/source/loader/layers/sanitizer/asan_interceptor.hpp b/source/loader/layers/sanitizer/asan_interceptor.hpp index 39c7705c99..3db8ce7460 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.hpp +++ b/source/loader/layers/sanitizer/asan_interceptor.hpp @@ -201,6 +201,12 @@ class SanitizerInterceptor { ur_result_t eraseMemBuffer(ur_mem_handle_t MemHandle); std::shared_ptr getMemBuffer(ur_mem_handle_t MemHandle); + ur_result_t holdAdapter(ur_adapter_handle_t Adapter) { + UR_CALL(getContext()->urDdiTable.Global.pfnAdapterRetain(Adapter)); + m_Adapters.push_back(Adapter); + return UR_RESULT_SUCCESS; + } + std::optional findAllocInfoByAddress(uptr Address); std::shared_ptr getContextInfo(ur_context_handle_t Context) { @@ -262,6 +268,8 @@ class SanitizerInterceptor { std::unique_ptr m_Quarantine; logger::Logger &logger; + + std::vector m_Adapters; }; } // namespace ur_sanitizer_layer diff --git a/source/loader/layers/sanitizer/ur_sanddi.cpp b/source/loader/layers/sanitizer/ur_sanddi.cpp index ef1e92f75b..9ac3a95ce6 100644 --- a/source/loader/layers/sanitizer/ur_sanddi.cpp +++ b/source/loader/layers/sanitizer/ur_sanddi.cpp @@ -37,6 +37,38 @@ ur_result_t setupContext(ur_context_handle_t Context, uint32_t numDevices, } // namespace +/////////////////////////////////////////////////////////////////////////////// +/// @brief Intercept function for urAdapterGet +__urdlllocal ur_result_t UR_APICALL urAdapterGet( + uint32_t + NumEntries, ///< [in] the number of adapters to be added to phAdapters. + ///< If phAdapters is not NULL, then NumEntries should be greater than + ///< zero, otherwise ::UR_RESULT_ERROR_INVALID_SIZE, + ///< will be returned. + ur_adapter_handle_t * + phAdapters, ///< [out][optional][range(0, NumEntries)] array of handle of adapters. + ///< If NumEntries is less than the number of adapters available, then + ///< ::urAdapterGet shall only retrieve that number of platforms. + uint32_t * + pNumAdapters ///< [out][optional] returns the total number of adapters available. +) { + auto pfnAdapterGet = getContext()->urDdiTable.Global.pfnAdapterGet; + + if (nullptr == pfnAdapterGet) { + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + + ur_result_t result = pfnAdapterGet(NumEntries, phAdapters, pNumAdapters); + if (result == UR_RESULT_SUCCESS) { + const uint32_t NumAdapters = pNumAdapters ? *pNumAdapters : NumEntries; + for (uint32_t i = 0; i < NumAdapters; ++i) { + getContext()->interceptor->holdAdapter(phAdapters[i]); + } + } + + return result; +} + /////////////////////////////////////////////////////////////////////////////// /// @brief Intercept function for urUSMHostAlloc __urdlllocal ur_result_t UR_APICALL urUSMHostAlloc( @@ -1274,6 +1306,38 @@ __urdlllocal ur_result_t UR_APICALL urKernelSetArgLocal( return result; } +/////////////////////////////////////////////////////////////////////////////// +/// @brief Exported function for filling application's Global table +/// with current process' addresses +/// +/// @returns +/// - ::UR_RESULT_SUCCESS +/// - ::UR_RESULT_ERROR_INVALID_NULL_POINTER +/// - ::UR_RESULT_ERROR_UNSUPPORTED_VERSION +__urdlllocal ur_result_t UR_APICALL urGetGlobalProcAddrTable( + ur_api_version_t version, ///< [in] API version requested + ur_global_dditable_t + *pDdiTable ///< [in,out] pointer to table of DDI function pointers +) { + auto &dditable = ur_sanitizer_layer::getContext()->urDdiTable.Global; + + if (nullptr == pDdiTable) { + return UR_RESULT_ERROR_INVALID_NULL_POINTER; + } + + if (UR_MAJOR_VERSION(ur_sanitizer_layer::getContext()->version) != + UR_MAJOR_VERSION(version) || + UR_MINOR_VERSION(ur_sanitizer_layer::getContext()->version) > + UR_MINOR_VERSION(version)) { + return UR_RESULT_ERROR_UNSUPPORTED_VERSION; + } + + ur_result_t result = UR_RESULT_SUCCESS; + + pDdiTable->pfnAdapterGet = ur_sanitizer_layer::urAdapterGet; + + return result; +} /////////////////////////////////////////////////////////////////////////////// /// @brief Exported function for filling application's Context table /// with current process' addresses @@ -1545,6 +1609,11 @@ ur_result_t context_t::init(ur_dditable_t *dditable, urDdiTable = *dditable; + if (UR_RESULT_SUCCESS == result) { + result = ur_sanitizer_layer::urGetGlobalProcAddrTable( + UR_API_VERSION_CURRENT, &dditable->Global); + } + if (UR_RESULT_SUCCESS == result) { result = ur_sanitizer_layer::urGetContextProcAddrTable( UR_API_VERSION_CURRENT, &dditable->Context); From 6449148bb54ccaf73a9260ae309f595bf19b0f9b Mon Sep 17 00:00:00 2001 From: "Zhao, Yang2" Date: Sun, 21 Jul 2024 22:42:41 -0700 Subject: [PATCH 02/12] Add UR_CALL --- source/loader/layers/sanitizer/ur_sanddi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/loader/layers/sanitizer/ur_sanddi.cpp b/source/loader/layers/sanitizer/ur_sanddi.cpp index 9ac3a95ce6..8aa99c9790 100644 --- a/source/loader/layers/sanitizer/ur_sanddi.cpp +++ b/source/loader/layers/sanitizer/ur_sanddi.cpp @@ -62,7 +62,7 @@ __urdlllocal ur_result_t UR_APICALL urAdapterGet( if (result == UR_RESULT_SUCCESS) { const uint32_t NumAdapters = pNumAdapters ? *pNumAdapters : NumEntries; for (uint32_t i = 0; i < NumAdapters; ++i) { - getContext()->interceptor->holdAdapter(phAdapters[i]); + UR_CALL(getContext()->interceptor->holdAdapter(phAdapters[i])); } } From ae7dea6def954379dbb91194c1e83af733e6954d Mon Sep 17 00:00:00 2001 From: "Zhao, Yang2" Date: Mon, 22 Jul 2024 01:40:27 -0700 Subject: [PATCH 03/12] using unordered_set --- source/loader/layers/sanitizer/asan_interceptor.hpp | 5 +++-- source/loader/layers/sanitizer/ur_sanddi.cpp | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/source/loader/layers/sanitizer/asan_interceptor.hpp b/source/loader/layers/sanitizer/asan_interceptor.hpp index 3db8ce7460..60e750cf8a 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.hpp +++ b/source/loader/layers/sanitizer/asan_interceptor.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include namespace ur_sanitizer_layer { @@ -203,7 +204,7 @@ class SanitizerInterceptor { ur_result_t holdAdapter(ur_adapter_handle_t Adapter) { UR_CALL(getContext()->urDdiTable.Global.pfnAdapterRetain(Adapter)); - m_Adapters.push_back(Adapter); + m_Adapters.insert(Adapter); return UR_RESULT_SUCCESS; } @@ -269,7 +270,7 @@ class SanitizerInterceptor { std::unique_ptr m_Quarantine; logger::Logger &logger; - std::vector m_Adapters; + std::unordered_set m_Adapters; }; } // namespace ur_sanitizer_layer diff --git a/source/loader/layers/sanitizer/ur_sanddi.cpp b/source/loader/layers/sanitizer/ur_sanddi.cpp index 8aa99c9790..7b7db694e5 100644 --- a/source/loader/layers/sanitizer/ur_sanddi.cpp +++ b/source/loader/layers/sanitizer/ur_sanddi.cpp @@ -1319,8 +1319,6 @@ __urdlllocal ur_result_t UR_APICALL urGetGlobalProcAddrTable( ur_global_dditable_t *pDdiTable ///< [in,out] pointer to table of DDI function pointers ) { - auto &dditable = ur_sanitizer_layer::getContext()->urDdiTable.Global; - if (nullptr == pDdiTable) { return UR_RESULT_ERROR_INVALID_NULL_POINTER; } From 9e6923fb2fb9af73279b74e576e3107a6abe965a Mon Sep 17 00:00:00 2001 From: "Zhao, Yang2" Date: Tue, 23 Jul 2024 19:54:50 -0700 Subject: [PATCH 04/12] wip --- test/layers/CMakeLists.txt | 4 + test/layers/sanitizer/CMakeLists.txt | 56 ++++++++ test/layers/sanitizer/fixtures.hpp | 176 +++++++++++++++++++++++ test/layers/sanitizer/lifetime.cpp | 27 ++++ test/layers/sanitizer/lifetime.out.match | 12 ++ 5 files changed, 275 insertions(+) create mode 100644 test/layers/sanitizer/CMakeLists.txt create mode 100644 test/layers/sanitizer/fixtures.hpp create mode 100644 test/layers/sanitizer/lifetime.cpp create mode 100644 test/layers/sanitizer/lifetime.out.match diff --git a/test/layers/CMakeLists.txt b/test/layers/CMakeLists.txt index 2c10a08518..fbf532c274 100644 --- a/test/layers/CMakeLists.txt +++ b/test/layers/CMakeLists.txt @@ -8,3 +8,7 @@ add_subdirectory(validation) if(UR_ENABLE_TRACING) add_subdirectory(tracing) endif() + +if(UR_ENABLE_SANITIZER) + add_subdirectory(sanitizer) +endif() diff --git a/test/layers/sanitizer/CMakeLists.txt b/test/layers/sanitizer/CMakeLists.txt new file mode 100644 index 0000000000..063c5ffc89 --- /dev/null +++ b/test/layers/sanitizer/CMakeLists.txt @@ -0,0 +1,56 @@ +# Copyright (C) 2023-2024 Intel Corporation +# Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions. +# See LICENSE.TXT +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set(UR_VALIDATION_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(VAL_TEST_PREFIX validation_test) + +function(add_validation_test_executable name) + add_ur_executable(${VAL_TEST_PREFIX}-${name} + ${ARGN}) + target_link_libraries(${VAL_TEST_PREFIX}-${name} + PRIVATE + ${PROJECT_NAME}::loader + ${PROJECT_NAME}::headers + ${PROJECT_NAME}::testing + ${PROJECT_NAME}::mock + GTest::gtest_main) +endfunction() + +function(set_validation_test_properties name) + set_tests_properties(${name} PROPERTIES LABELS "validation") + set_property(TEST ${name} PROPERTY ENVIRONMENT + "UR_ENABLE_LAYERS=UR_LAYER_FULL_VALIDATION" + "UR_ADAPTERS_FORCE_LOAD=\"$\"" + "UR_LOG_VALIDATION=level:debug\;flush:debug\;output:stdout") +endfunction() + +function(add_validation_test name) + add_validation_test_executable(${name} ${ARGN}) + + add_test(NAME ${name} + COMMAND ${VAL_TEST_PREFIX}-${name} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + set_validation_test_properties(${name}) +endfunction() + +function(add_validation_match_test name) + add_validation_test_executable(${name} ${ARGN}) + + add_test(NAME ${name} + COMMAND ${CMAKE_COMMAND} + -D MODE=stdout + -D TEST_FILE=$ + -D MATCH_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${name}.out.match + -P ${PROJECT_SOURCE_DIR}/cmake/match.cmake + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + set_validation_test_properties(${name}) +endfunction() + +add_validation_test(parameters parameters.cpp) +add_validation_match_test(leaks leaks.out.match leaks.cpp) +add_validation_match_test(leaks_mt leaks_mt.out.match leaks_mt.cpp) +add_validation_match_test(lifetime lifetime.out.match lifetime.cpp) diff --git a/test/layers/sanitizer/fixtures.hpp b/test/layers/sanitizer/fixtures.hpp new file mode 100644 index 0000000000..9e261f0a1d --- /dev/null +++ b/test/layers/sanitizer/fixtures.hpp @@ -0,0 +1,176 @@ +// Copyright (C) 2023-2024 Intel Corporation +// Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions. +// See LICENSE.TXT +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef UR_VALIDATION_TEST_HELPERS_H +#define UR_VALIDATION_TEST_HELPERS_H + +#include +#include + +#include +#include + +struct urTest : ::testing::Test { + + void SetUp() override { + ASSERT_EQ(urLoaderConfigCreate(&loader_config), UR_RESULT_SUCCESS); + ASSERT_EQ(urLoaderConfigEnableLayer(loader_config, + "UR_LAYER_FULL_VALIDATION"), + UR_RESULT_SUCCESS); + ur_device_init_flags_t device_flags = 0; + ASSERT_EQ(urLoaderInit(device_flags, loader_config), UR_RESULT_SUCCESS); + } + + void TearDown() override { + if (loader_config) { + ASSERT_EQ(urLoaderConfigRelease(loader_config), UR_RESULT_SUCCESS); + } + ASSERT_EQ(urLoaderTearDown(), UR_RESULT_SUCCESS); + } + + ur_loader_config_handle_t loader_config = nullptr; +}; + +struct valAdaptersTest : urTest { + + void SetUp() override { + urTest::SetUp(); + + uint32_t adapter_count; + ASSERT_EQ(urAdapterGet(0, nullptr, &adapter_count), UR_RESULT_SUCCESS); + ASSERT_GT(adapter_count, 0); + adapters.resize(adapter_count); + ASSERT_EQ(urAdapterGet(adapter_count, adapters.data(), nullptr), + UR_RESULT_SUCCESS); + } + + void TearDown() override { + for (auto adapter : adapters) { + ASSERT_EQ(urAdapterRelease(adapter), UR_RESULT_SUCCESS); + } + urTest::TearDown(); + } + + std::vector adapters; +}; + +struct valAdapterTest : valAdaptersTest { + + void SetUp() override { + valAdaptersTest::SetUp(); + adapter = adapters[0]; // TODO - which to choose? + } + + ur_adapter_handle_t adapter; +}; + +struct valPlatformsTest : valAdaptersTest { + + void SetUp() override { + valAdaptersTest::SetUp(); + + uint32_t count; + ASSERT_EQ(urPlatformGet(adapters.data(), + static_cast(adapters.size()), 0, + nullptr, &count), + UR_RESULT_SUCCESS); + ASSERT_GT(count, 0); + platforms.resize(count); + ASSERT_EQ(urPlatformGet(adapters.data(), + static_cast(adapters.size()), count, + platforms.data(), nullptr), + UR_RESULT_SUCCESS); + } + + std::vector platforms; +}; + +struct valPlatformTest : valPlatformsTest { + + void SetUp() override { + valPlatformsTest::SetUp(); + ASSERT_GE(platforms.size(), 1); + platform = platforms[0]; // TODO - which to choose? + } + + ur_platform_handle_t platform; +}; + +struct valAllDevicesTest : valPlatformTest { + + void SetUp() override { + valPlatformTest::SetUp(); + + uint32_t count = 0; + if (urDeviceGet(platform, UR_DEVICE_TYPE_ALL, 0, nullptr, &count) || + count == 0) { + FAIL() << "Failed to get devices"; + } + + devices.resize(count); + if (urDeviceGet(platform, UR_DEVICE_TYPE_ALL, count, devices.data(), + nullptr)) { + FAIL() << "Failed to get devices"; + } + } + + void TearDown() override { + for (auto device : devices) { + ASSERT_EQ(urDeviceRelease(device), UR_RESULT_SUCCESS); + } + valPlatformTest::TearDown(); + } + + std::vector devices; +}; + +// We use this to avoid segfaults in the mock adapter when we're doing stuff +// like double releases in the leak detection tests. +inline ur_result_t genericSuccessCallback(void *) { return UR_RESULT_SUCCESS; }; + +// This returns valid (non-null) handles that we can safely leak. +inline ur_result_t fakeContext_urContextCreate(void *pParams) { + static std::atomic_int handle = 42; + auto params = *static_cast(pParams); + // There are two casts because windows doesn't implicitly extend the 32 bit + // result of atomic_int::operator++. + **params.pphContext = + reinterpret_cast(static_cast(handle++)); + return UR_RESULT_SUCCESS; +} + +struct valDeviceTest : valAllDevicesTest { + + void SetUp() override { + valAllDevicesTest::SetUp(); + ASSERT_GE(devices.size(), 1); + device = devices[0]; + mock::getCallbacks().set_replace_callback("urContextRetain", + &genericSuccessCallback); + mock::getCallbacks().set_replace_callback("urContextRelease", + &genericSuccessCallback); + mock::getCallbacks().set_replace_callback("urContextCreate", + &fakeContext_urContextCreate); + } + + void TearDown() override { + mock::getCallbacks().resetCallbacks(); + valAllDevicesTest::TearDown(); + } + ur_device_handle_t device; +}; + +struct valDeviceTestMultithreaded : valDeviceTest, + public ::testing::WithParamInterface { + void SetUp() override { + valDeviceTest::SetUp(); + + threadCount = GetParam(); + } + + int threadCount; +}; + +#endif // UR_VALIDATION_TEST_HELPERS_H diff --git a/test/layers/sanitizer/lifetime.cpp b/test/layers/sanitizer/lifetime.cpp new file mode 100644 index 0000000000..bec49826eb --- /dev/null +++ b/test/layers/sanitizer/lifetime.cpp @@ -0,0 +1,27 @@ +// Copyright (C) 2023-2024 Intel Corporation +// Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions. +// See LICENSE.TXT +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "fixtures.hpp" + +TEST_F(urTest, testUrAdapterHandleLifetimeExpectFail) { + size_t size = 0; + ur_adapter_handle_t adapter = (ur_adapter_handle_t)0xC0FFEE; + ur_adapter_info_t info_type = UR_ADAPTER_INFO_BACKEND; + urAdapterGetInfo(adapter, info_type, 0, nullptr, &size); +} + +TEST_F(valAdapterTest, testUrAdapterHandleLifetimeExpectSuccess) { + size_t size = 0; + ur_adapter_info_t info_type = UR_ADAPTER_INFO_BACKEND; + urAdapterGetInfo(adapter, info_type, 0, nullptr, &size); +} + +TEST_F(valAdapterTest, testUrAdapterHandleTypeMismatchExpectFail) { + size_t size = 0; + // Use valid adapter handle with incorrect cast. + ur_device_handle_t device = (ur_device_handle_t)adapter; + ur_device_info_t info_type = UR_DEVICE_INFO_BACKEND_RUNTIME_VERSION; + urDeviceGetInfo(device, info_type, 0, nullptr, &size); +} diff --git a/test/layers/sanitizer/lifetime.out.match b/test/layers/sanitizer/lifetime.out.match new file mode 100644 index 0000000000..f73bd71ba4 --- /dev/null +++ b/test/layers/sanitizer/lifetime.out.match @@ -0,0 +1,12 @@ +{{IGNORE}} +[ RUN ] urTest.testUrAdapterHandleLifetimeExpectFail + [ERROR]: There are no valid references to handle {{[0-9xa-fA-F]+}} +{{IGNORE}} +[ RUN ] valAdapterTest.testUrAdapterHandleLifetimeExpectSuccess +[DEBUG]: Reference count for handle {{[0-9xa-fA-F]+}} changed to 1 +{{^(?!.*There are no valid references to handle).*$}} +{{IGNORE}} +[ RUN ] valAdapterTest.testUrAdapterHandleTypeMismatchExpectFail +[DEBUG]: Reference count for handle {{[0-9xa-fA-F]+}} changed to 1 +[ERROR]: There are no valid references to handle {{[0-9xa-fA-F]+}} +{{IGNORE}} From 5859e3c1782d9f41bb637edb4fe6106e527b9062 Mon Sep 17 00:00:00 2001 From: "Zhao, Yang2" Date: Fri, 2 Aug 2024 01:40:59 -0700 Subject: [PATCH 05/12] fix crash --- source/loader/layers/sanitizer/asan_interceptor.cpp | 6 ++++++ source/loader/layers/sanitizer/ur_sanddi.cpp | 2 +- source/loader/ur_lib.cpp | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/source/loader/layers/sanitizer/asan_interceptor.cpp b/source/loader/layers/sanitizer/asan_interceptor.cpp index 927fae4707..934ad4b4be 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.cpp +++ b/source/loader/layers/sanitizer/asan_interceptor.cpp @@ -186,6 +186,12 @@ SanitizerInterceptor::~SanitizerInterceptor() { DestroyShadowMemoryOnPVC(); DestroyShadowMemoryOnDG2(); + m_Quarantine = nullptr; + m_MemBufferMap.clear(); + m_AllocationMap.clear(); + m_KernelMap.clear(); + m_ContextMap.clear(); + for (auto Adapter : m_Adapters) { getContext()->urDdiTable.Global.pfnAdapterRelease(Adapter); } diff --git a/source/loader/layers/sanitizer/ur_sanddi.cpp b/source/loader/layers/sanitizer/ur_sanddi.cpp index 9cdcb19a77..8718936dc4 100644 --- a/source/loader/layers/sanitizer/ur_sanddi.cpp +++ b/source/loader/layers/sanitizer/ur_sanddi.cpp @@ -66,7 +66,7 @@ __urdlllocal ur_result_t UR_APICALL urAdapterGet( } ur_result_t result = pfnAdapterGet(NumEntries, phAdapters, pNumAdapters); - if (result == UR_RESULT_SUCCESS) { + if (result == UR_RESULT_SUCCESS && phAdapters) { const uint32_t NumAdapters = pNumAdapters ? *pNumAdapters : NumEntries; for (uint32_t i = 0; i < NumAdapters; ++i) { UR_CALL(getContext()->interceptor->holdAdapter(phAdapters[i])); diff --git a/source/loader/ur_lib.cpp b/source/loader/ur_lib.cpp index 12b159b0e5..9aad7159c3 100644 --- a/source/loader/ur_lib.cpp +++ b/source/loader/ur_lib.cpp @@ -57,7 +57,8 @@ void context_t::initLayers() const { } void context_t::tearDownLayers() const { - for (auto &[layer, destroy] : layers) { + for (auto it = layers.rbegin(); it != layers.rend(); ++it) { + auto [layer, destroy] = *it; layer->tearDown(); destroy(); } From 982667e30c0af65421953aaa4bfd883b72d3c0b3 Mon Sep 17 00:00:00 2001 From: "Zhao, Yang2" Date: Mon, 5 Aug 2024 19:24:03 -0700 Subject: [PATCH 06/12] fix repeat hold adapter handle --- source/loader/layers/sanitizer/asan_interceptor.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/loader/layers/sanitizer/asan_interceptor.hpp b/source/loader/layers/sanitizer/asan_interceptor.hpp index 60e750cf8a..b8c7eb24d0 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.hpp +++ b/source/loader/layers/sanitizer/asan_interceptor.hpp @@ -203,6 +203,9 @@ class SanitizerInterceptor { std::shared_ptr getMemBuffer(ur_mem_handle_t MemHandle); ur_result_t holdAdapter(ur_adapter_handle_t Adapter) { + if (m_Adapters.find(Adapter) != m_Adapters.end()) { + return UR_RESULT_SUCCESS; + } UR_CALL(getContext()->urDdiTable.Global.pfnAdapterRetain(Adapter)); m_Adapters.insert(Adapter); return UR_RESULT_SUCCESS; From d67cfecb00aca3ae81624851f271e4fe5bdd4edf Mon Sep 17 00:00:00 2001 From: "Zhao, Yang2" Date: Mon, 5 Aug 2024 23:52:19 -0700 Subject: [PATCH 07/12] update test --- test/layers/sanitizer/CMakeLists.txt | 39 +++-- test/layers/sanitizer/asan.cpp | 55 +++++++ test/layers/sanitizer/fixtures.hpp | 176 ----------------------- test/layers/sanitizer/lifetime.cpp | 27 ---- test/layers/sanitizer/lifetime.out.match | 12 -- 5 files changed, 72 insertions(+), 237 deletions(-) create mode 100644 test/layers/sanitizer/asan.cpp delete mode 100644 test/layers/sanitizer/fixtures.hpp delete mode 100644 test/layers/sanitizer/lifetime.cpp delete mode 100644 test/layers/sanitizer/lifetime.out.match diff --git a/test/layers/sanitizer/CMakeLists.txt b/test/layers/sanitizer/CMakeLists.txt index 063c5ffc89..cdfac295f6 100644 --- a/test/layers/sanitizer/CMakeLists.txt +++ b/test/layers/sanitizer/CMakeLists.txt @@ -3,13 +3,13 @@ # See LICENSE.TXT # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -set(UR_VALIDATION_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(VAL_TEST_PREFIX validation_test) +set(UR_SANITIZER_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(SAN_TEST_PREFIX sanitizer_test) -function(add_validation_test_executable name) - add_ur_executable(${VAL_TEST_PREFIX}-${name} +function(add_sanitizer_test_executable name) + add_ur_executable(${SAN_TEST_PREFIX}-${name} ${ARGN}) - target_link_libraries(${VAL_TEST_PREFIX}-${name} + target_link_libraries(${SAN_TEST_PREFIX}-${name} PRIVATE ${PROJECT_NAME}::loader ${PROJECT_NAME}::headers @@ -18,39 +18,34 @@ function(add_validation_test_executable name) GTest::gtest_main) endfunction() -function(set_validation_test_properties name) - set_tests_properties(${name} PROPERTIES LABELS "validation") +function(set_sanitizer_test_properties name) + set_tests_properties(${name} PROPERTIES LABELS "sanitizer") set_property(TEST ${name} PROPERTY ENVIRONMENT - "UR_ENABLE_LAYERS=UR_LAYER_FULL_VALIDATION" - "UR_ADAPTERS_FORCE_LOAD=\"$\"" - "UR_LOG_VALIDATION=level:debug\;flush:debug\;output:stdout") + "UR_LOG_SANITIZER=level:debug\;flush:debug\;output:stdout") endfunction() -function(add_validation_test name) - add_validation_test_executable(${name} ${ARGN}) +function(add_sanitizer_test name) + add_sanitizer_test_executable(${name} ${ARGN}) add_test(NAME ${name} - COMMAND ${VAL_TEST_PREFIX}-${name} + COMMAND ${SAN_TEST_PREFIX}-${name} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - set_validation_test_properties(${name}) + set_sanitizer_test_properties(${name}) endfunction() -function(add_validation_match_test name) - add_validation_test_executable(${name} ${ARGN}) +function(add_sanitizer_match_test name) + add_sanitizer_test_executable(${name} ${ARGN}) add_test(NAME ${name} COMMAND ${CMAKE_COMMAND} -D MODE=stdout - -D TEST_FILE=$ + -D TEST_FILE=$ -D MATCH_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${name}.out.match -P ${PROJECT_SOURCE_DIR}/cmake/match.cmake WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - set_validation_test_properties(${name}) + set_sanitizer_test_properties(${name}) endfunction() -add_validation_test(parameters parameters.cpp) -add_validation_match_test(leaks leaks.out.match leaks.cpp) -add_validation_match_test(leaks_mt leaks_mt.out.match leaks_mt.cpp) -add_validation_match_test(lifetime lifetime.out.match lifetime.cpp) +add_sanitizer_test(asan asan.cpp) diff --git a/test/layers/sanitizer/asan.cpp b/test/layers/sanitizer/asan.cpp new file mode 100644 index 0000000000..ff6c1b8b95 --- /dev/null +++ b/test/layers/sanitizer/asan.cpp @@ -0,0 +1,55 @@ +/* + * + * Copyright (C) 2024 Intel Corporation + * + * Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions. + * See LICENSE.TXT + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + * @file codeloc.cpp + * + */ + +#include +#include + +TEST(DeviceASan, Initialization) { + ur_result_t status; + + ur_loader_config_handle_t loaderConfig; + status = urLoaderConfigCreate(&loaderConfig); + ASSERT_EQ(status, UR_RESULT_SUCCESS); + status = urLoaderConfigEnableLayer(loaderConfig, "UR_LAYER_ASAN"); + ASSERT_EQ(status, UR_RESULT_SUCCESS); + + status = urLoaderInit(0, loaderConfig); + ASSERT_EQ(status, UR_RESULT_SUCCESS); + + ur_adapter_handle_t adapter; + status = urAdapterGet(1, &adapter, nullptr); + ASSERT_EQ(status, UR_RESULT_SUCCESS); + + ur_platform_handle_t platform; + status = urPlatformGet(&adapter, 1, 1, &platform, nullptr); + ASSERT_EQ(status, UR_RESULT_SUCCESS); + + ur_device_handle_t device; + status = urDeviceGet(platform, UR_DEVICE_TYPE_DEFAULT, 1, &device, nullptr); + ASSERT_EQ(status, UR_RESULT_SUCCESS); + + ur_context_handle_t context; + status = urContextCreate(1, &device, nullptr, &context); + ASSERT_EQ(status, UR_RESULT_SUCCESS); + + status = urDeviceRelease(device); + ASSERT_EQ(status, UR_RESULT_SUCCESS); + + status = urAdapterRelease(adapter); + ASSERT_EQ(status, UR_RESULT_SUCCESS); + + status = urLoaderTearDown(); + ASSERT_EQ(status, UR_RESULT_SUCCESS); + + status = urLoaderConfigRelease(loaderConfig); + ASSERT_EQ(status, UR_RESULT_SUCCESS); +} diff --git a/test/layers/sanitizer/fixtures.hpp b/test/layers/sanitizer/fixtures.hpp deleted file mode 100644 index 9e261f0a1d..0000000000 --- a/test/layers/sanitizer/fixtures.hpp +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (C) 2023-2024 Intel Corporation -// Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See LICENSE.TXT -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef UR_VALIDATION_TEST_HELPERS_H -#define UR_VALIDATION_TEST_HELPERS_H - -#include -#include - -#include -#include - -struct urTest : ::testing::Test { - - void SetUp() override { - ASSERT_EQ(urLoaderConfigCreate(&loader_config), UR_RESULT_SUCCESS); - ASSERT_EQ(urLoaderConfigEnableLayer(loader_config, - "UR_LAYER_FULL_VALIDATION"), - UR_RESULT_SUCCESS); - ur_device_init_flags_t device_flags = 0; - ASSERT_EQ(urLoaderInit(device_flags, loader_config), UR_RESULT_SUCCESS); - } - - void TearDown() override { - if (loader_config) { - ASSERT_EQ(urLoaderConfigRelease(loader_config), UR_RESULT_SUCCESS); - } - ASSERT_EQ(urLoaderTearDown(), UR_RESULT_SUCCESS); - } - - ur_loader_config_handle_t loader_config = nullptr; -}; - -struct valAdaptersTest : urTest { - - void SetUp() override { - urTest::SetUp(); - - uint32_t adapter_count; - ASSERT_EQ(urAdapterGet(0, nullptr, &adapter_count), UR_RESULT_SUCCESS); - ASSERT_GT(adapter_count, 0); - adapters.resize(adapter_count); - ASSERT_EQ(urAdapterGet(adapter_count, adapters.data(), nullptr), - UR_RESULT_SUCCESS); - } - - void TearDown() override { - for (auto adapter : adapters) { - ASSERT_EQ(urAdapterRelease(adapter), UR_RESULT_SUCCESS); - } - urTest::TearDown(); - } - - std::vector adapters; -}; - -struct valAdapterTest : valAdaptersTest { - - void SetUp() override { - valAdaptersTest::SetUp(); - adapter = adapters[0]; // TODO - which to choose? - } - - ur_adapter_handle_t adapter; -}; - -struct valPlatformsTest : valAdaptersTest { - - void SetUp() override { - valAdaptersTest::SetUp(); - - uint32_t count; - ASSERT_EQ(urPlatformGet(adapters.data(), - static_cast(adapters.size()), 0, - nullptr, &count), - UR_RESULT_SUCCESS); - ASSERT_GT(count, 0); - platforms.resize(count); - ASSERT_EQ(urPlatformGet(adapters.data(), - static_cast(adapters.size()), count, - platforms.data(), nullptr), - UR_RESULT_SUCCESS); - } - - std::vector platforms; -}; - -struct valPlatformTest : valPlatformsTest { - - void SetUp() override { - valPlatformsTest::SetUp(); - ASSERT_GE(platforms.size(), 1); - platform = platforms[0]; // TODO - which to choose? - } - - ur_platform_handle_t platform; -}; - -struct valAllDevicesTest : valPlatformTest { - - void SetUp() override { - valPlatformTest::SetUp(); - - uint32_t count = 0; - if (urDeviceGet(platform, UR_DEVICE_TYPE_ALL, 0, nullptr, &count) || - count == 0) { - FAIL() << "Failed to get devices"; - } - - devices.resize(count); - if (urDeviceGet(platform, UR_DEVICE_TYPE_ALL, count, devices.data(), - nullptr)) { - FAIL() << "Failed to get devices"; - } - } - - void TearDown() override { - for (auto device : devices) { - ASSERT_EQ(urDeviceRelease(device), UR_RESULT_SUCCESS); - } - valPlatformTest::TearDown(); - } - - std::vector devices; -}; - -// We use this to avoid segfaults in the mock adapter when we're doing stuff -// like double releases in the leak detection tests. -inline ur_result_t genericSuccessCallback(void *) { return UR_RESULT_SUCCESS; }; - -// This returns valid (non-null) handles that we can safely leak. -inline ur_result_t fakeContext_urContextCreate(void *pParams) { - static std::atomic_int handle = 42; - auto params = *static_cast(pParams); - // There are two casts because windows doesn't implicitly extend the 32 bit - // result of atomic_int::operator++. - **params.pphContext = - reinterpret_cast(static_cast(handle++)); - return UR_RESULT_SUCCESS; -} - -struct valDeviceTest : valAllDevicesTest { - - void SetUp() override { - valAllDevicesTest::SetUp(); - ASSERT_GE(devices.size(), 1); - device = devices[0]; - mock::getCallbacks().set_replace_callback("urContextRetain", - &genericSuccessCallback); - mock::getCallbacks().set_replace_callback("urContextRelease", - &genericSuccessCallback); - mock::getCallbacks().set_replace_callback("urContextCreate", - &fakeContext_urContextCreate); - } - - void TearDown() override { - mock::getCallbacks().resetCallbacks(); - valAllDevicesTest::TearDown(); - } - ur_device_handle_t device; -}; - -struct valDeviceTestMultithreaded : valDeviceTest, - public ::testing::WithParamInterface { - void SetUp() override { - valDeviceTest::SetUp(); - - threadCount = GetParam(); - } - - int threadCount; -}; - -#endif // UR_VALIDATION_TEST_HELPERS_H diff --git a/test/layers/sanitizer/lifetime.cpp b/test/layers/sanitizer/lifetime.cpp deleted file mode 100644 index bec49826eb..0000000000 --- a/test/layers/sanitizer/lifetime.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (C) 2023-2024 Intel Corporation -// Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See LICENSE.TXT -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include "fixtures.hpp" - -TEST_F(urTest, testUrAdapterHandleLifetimeExpectFail) { - size_t size = 0; - ur_adapter_handle_t adapter = (ur_adapter_handle_t)0xC0FFEE; - ur_adapter_info_t info_type = UR_ADAPTER_INFO_BACKEND; - urAdapterGetInfo(adapter, info_type, 0, nullptr, &size); -} - -TEST_F(valAdapterTest, testUrAdapterHandleLifetimeExpectSuccess) { - size_t size = 0; - ur_adapter_info_t info_type = UR_ADAPTER_INFO_BACKEND; - urAdapterGetInfo(adapter, info_type, 0, nullptr, &size); -} - -TEST_F(valAdapterTest, testUrAdapterHandleTypeMismatchExpectFail) { - size_t size = 0; - // Use valid adapter handle with incorrect cast. - ur_device_handle_t device = (ur_device_handle_t)adapter; - ur_device_info_t info_type = UR_DEVICE_INFO_BACKEND_RUNTIME_VERSION; - urDeviceGetInfo(device, info_type, 0, nullptr, &size); -} diff --git a/test/layers/sanitizer/lifetime.out.match b/test/layers/sanitizer/lifetime.out.match deleted file mode 100644 index f73bd71ba4..0000000000 --- a/test/layers/sanitizer/lifetime.out.match +++ /dev/null @@ -1,12 +0,0 @@ -{{IGNORE}} -[ RUN ] urTest.testUrAdapterHandleLifetimeExpectFail - [ERROR]: There are no valid references to handle {{[0-9xa-fA-F]+}} -{{IGNORE}} -[ RUN ] valAdapterTest.testUrAdapterHandleLifetimeExpectSuccess -[DEBUG]: Reference count for handle {{[0-9xa-fA-F]+}} changed to 1 -{{^(?!.*There are no valid references to handle).*$}} -{{IGNORE}} -[ RUN ] valAdapterTest.testUrAdapterHandleTypeMismatchExpectFail -[DEBUG]: Reference count for handle {{[0-9xa-fA-F]+}} changed to 1 -[ERROR]: There are no valid references to handle {{[0-9xa-fA-F]+}} -{{IGNORE}} From 250f7598fb6aae8692f3cd9d545751758a2c319a Mon Sep 17 00:00:00 2001 From: "Zhao, Yang2" Date: Tue, 6 Aug 2024 00:16:03 -0700 Subject: [PATCH 08/12] add mutex for adapter --- source/loader/layers/sanitizer/asan_interceptor.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/loader/layers/sanitizer/asan_interceptor.hpp b/source/loader/layers/sanitizer/asan_interceptor.hpp index b8c7eb24d0..99badbca02 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.hpp +++ b/source/loader/layers/sanitizer/asan_interceptor.hpp @@ -203,6 +203,7 @@ class SanitizerInterceptor { std::shared_ptr getMemBuffer(ur_mem_handle_t MemHandle); ur_result_t holdAdapter(ur_adapter_handle_t Adapter) { + std::scoped_lock Guard(m_AdaptersMutex); if (m_Adapters.find(Adapter) != m_Adapters.end()) { return UR_RESULT_SUCCESS; } @@ -274,6 +275,7 @@ class SanitizerInterceptor { logger::Logger &logger; std::unordered_set m_Adapters; + ur_shared_mutex m_AdaptersMutex; }; } // namespace ur_sanitizer_layer From 864da649399d5c615ffe102666dbc4091f42384b Mon Sep 17 00:00:00 2001 From: "Zhao, Yang2" Date: Tue, 6 Aug 2024 21:48:22 -0700 Subject: [PATCH 09/12] fix test --- test/layers/sanitizer/asan.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/layers/sanitizer/asan.cpp b/test/layers/sanitizer/asan.cpp index ff6c1b8b95..7b7d86ee6c 100644 --- a/test/layers/sanitizer/asan.cpp +++ b/test/layers/sanitizer/asan.cpp @@ -41,6 +41,9 @@ TEST(DeviceASan, Initialization) { status = urContextCreate(1, &device, nullptr, &context); ASSERT_EQ(status, UR_RESULT_SUCCESS); + status = urContextRelease(context); + ASSERT_EQ(status, UR_RESULT_SUCCESS); + status = urDeviceRelease(device); ASSERT_EQ(status, UR_RESULT_SUCCESS); From e264cc184958ae8514c4a5d4677d9ee50604a2c5 Mon Sep 17 00:00:00 2001 From: "Zhao, Yang2" Date: Wed, 14 Aug 2024 14:37:46 +0800 Subject: [PATCH 10/12] address comments --- source/loader/layers/sanitizer/asan_interceptor.cpp | 2 ++ source/loader/layers/sanitizer/asan_interceptor.hpp | 5 ++--- test/layers/sanitizer/asan.cpp | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/source/loader/layers/sanitizer/asan_interceptor.cpp b/source/loader/layers/sanitizer/asan_interceptor.cpp index 1645fc4cf8..d49ee7ee80 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.cpp +++ b/source/loader/layers/sanitizer/asan_interceptor.cpp @@ -187,6 +187,8 @@ SanitizerInterceptor::~SanitizerInterceptor() { DestroyShadowMemoryOnPVC(); DestroyShadowMemoryOnDG2(); + // We must release these objects before releasing adapters, since + // they may use the adapter in their destruction process m_Quarantine = nullptr; m_MemBufferMap.clear(); m_AllocationMap.clear(); diff --git a/source/loader/layers/sanitizer/asan_interceptor.hpp b/source/loader/layers/sanitizer/asan_interceptor.hpp index 07163ad125..591bee2c3a 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.hpp +++ b/source/loader/layers/sanitizer/asan_interceptor.hpp @@ -49,9 +49,8 @@ struct DeviceInfo { std::queue> Quarantine; size_t QuarantineSize = 0; - // TODO: re-enable retaining and releasing device handles in DeviceInfo - // constructor/destructor. See PR - // https://github.com/oneapi-src/unified-runtime/pull/1883 + // Device handles are special and alive in the whole process lifetime, + // so we needn't retain&release here. explicit DeviceInfo(ur_device_handle_t Device) : Handle(Device) {} ur_result_t allocShadowMemory(ur_context_handle_t Context); diff --git a/test/layers/sanitizer/asan.cpp b/test/layers/sanitizer/asan.cpp index 7b7d86ee6c..67f6ffff16 100644 --- a/test/layers/sanitizer/asan.cpp +++ b/test/layers/sanitizer/asan.cpp @@ -6,7 +6,7 @@ * See LICENSE.TXT * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception * - * @file codeloc.cpp + * @file asan.cpp * */ From 74d30dca30d33b7e7e30e7ece5ee514ddd6d5e4b Mon Sep 17 00:00:00 2001 From: "Zhao, Yang2" Date: Wed, 14 Aug 2024 14:38:57 +0800 Subject: [PATCH 11/12] fix comments --- source/loader/layers/sanitizer/asan_interceptor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/loader/layers/sanitizer/asan_interceptor.cpp b/source/loader/layers/sanitizer/asan_interceptor.cpp index d49ee7ee80..ec1d5e8fad 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.cpp +++ b/source/loader/layers/sanitizer/asan_interceptor.cpp @@ -188,7 +188,7 @@ SanitizerInterceptor::~SanitizerInterceptor() { DestroyShadowMemoryOnDG2(); // We must release these objects before releasing adapters, since - // they may use the adapter in their destruction process + // they may use the adapter in their destructor m_Quarantine = nullptr; m_MemBufferMap.clear(); m_AllocationMap.clear(); From fe18b4ad9bd96e5aa2c6dc2391610b409c6e9ac7 Mon Sep 17 00:00:00 2001 From: "Zhao, Yang2" Date: Thu, 15 Aug 2024 18:01:28 +0800 Subject: [PATCH 12/12] fix reviews --- source/loader/layers/sanitizer/ur_sanddi.cpp | 1 + test/layers/sanitizer/CMakeLists.txt | 14 -------------- test/layers/sanitizer/asan.cpp | 2 +- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/source/loader/layers/sanitizer/ur_sanddi.cpp b/source/loader/layers/sanitizer/ur_sanddi.cpp index 603c37d9e3..4057f4604b 100644 --- a/source/loader/layers/sanitizer/ur_sanddi.cpp +++ b/source/loader/layers/sanitizer/ur_sanddi.cpp @@ -1323,6 +1323,7 @@ __urdlllocal ur_result_t UR_APICALL urKernelSetArgLocal( return result; } +/////////////////////////////////////////////////////////////////////////////// /// @brief Intercept function for urKernelSetArgPointer __urdlllocal ur_result_t UR_APICALL urKernelSetArgPointer( ur_kernel_handle_t hKernel, ///< [in] handle of the kernel object diff --git a/test/layers/sanitizer/CMakeLists.txt b/test/layers/sanitizer/CMakeLists.txt index cdfac295f6..a9601a89c8 100644 --- a/test/layers/sanitizer/CMakeLists.txt +++ b/test/layers/sanitizer/CMakeLists.txt @@ -34,18 +34,4 @@ function(add_sanitizer_test name) set_sanitizer_test_properties(${name}) endfunction() -function(add_sanitizer_match_test name) - add_sanitizer_test_executable(${name} ${ARGN}) - - add_test(NAME ${name} - COMMAND ${CMAKE_COMMAND} - -D MODE=stdout - -D TEST_FILE=$ - -D MATCH_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${name}.out.match - -P ${PROJECT_SOURCE_DIR}/cmake/match.cmake - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - - set_sanitizer_test_properties(${name}) -endfunction() - add_sanitizer_test(asan asan.cpp) diff --git a/test/layers/sanitizer/asan.cpp b/test/layers/sanitizer/asan.cpp index 67f6ffff16..0fbfe4cefe 100644 --- a/test/layers/sanitizer/asan.cpp +++ b/test/layers/sanitizer/asan.cpp @@ -13,7 +13,7 @@ #include #include -TEST(DeviceASan, Initialization) { +TEST(DeviceAsan, Initialization) { ur_result_t status; ur_loader_config_handle_t loaderConfig;