diff --git a/source/adapters/null/ur_null.cpp b/source/adapters/null/ur_null.cpp index 5653ca57db..d200712178 100644 --- a/source/adapters/null/ur_null.cpp +++ b/source/adapters/null/ur_null.cpp @@ -142,5 +142,68 @@ context_t::context_t() { } return UR_RESULT_SUCCESS; }; + + ////////////////////////////////////////////////////////////////////////// + urDdiTable.USM.pfnHostAlloc = + [](ur_context_handle_t hContext, const ur_usm_desc_t *pUSMDesc, + ur_usm_pool_handle_t pool, size_t size, void **ppMem) { + if (size == 0) { + *ppMem = nullptr; + return UR_RESULT_ERROR_UNSUPPORTED_SIZE; + } + *ppMem = malloc(size); + if (ppMem == nullptr) { + return UR_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + return UR_RESULT_SUCCESS; + }; + + ////////////////////////////////////////////////////////////////////////// + urDdiTable.USM.pfnDeviceAlloc = + [](ur_context_handle_t hContext, ur_device_handle_t hDevice, + const ur_usm_desc_t *pUSMDesc, ur_usm_pool_handle_t pool, + size_t size, void **ppMem) { + if (size == 0) { + *ppMem = nullptr; + return UR_RESULT_ERROR_UNSUPPORTED_SIZE; + } + *ppMem = malloc(size); + if (ppMem == nullptr) { + return UR_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + return UR_RESULT_SUCCESS; + }; + + ////////////////////////////////////////////////////////////////////////// + urDdiTable.USM.pfnFree = [](ur_context_handle_t hContext, void *pMem) { + free(pMem); + return UR_RESULT_SUCCESS; + }; + + ////////////////////////////////////////////////////////////////////////// + urDdiTable.USM.pfnGetMemAllocInfo = + [](ur_context_handle_t hContext, const void *pMem, + ur_usm_alloc_info_t propName, size_t propSize, void *pPropValue, + size_t *pPropSizeRet) { + switch (propName) { + case UR_USM_ALLOC_INFO_TYPE: + *reinterpret_cast(pPropValue) = + pMem ? UR_USM_TYPE_DEVICE : UR_USM_TYPE_UNKNOWN; + if (pPropSizeRet != nullptr) { + *pPropSizeRet = sizeof(ur_usm_type_t); + } + break; + case UR_USM_ALLOC_INFO_SIZE: + *reinterpret_cast(pPropValue) = pMem ? SIZE_MAX : 0; + if (pPropSizeRet != nullptr) { + *pPropSizeRet = sizeof(size_t); + } + break; + default: + pPropValue = nullptr; + break; + } + return UR_RESULT_SUCCESS; + }; } } // namespace driver diff --git a/test/conformance/CMakeLists.txt b/test/conformance/CMakeLists.txt index 2b2c5238c6..0eedd8add1 100644 --- a/test/conformance/CMakeLists.txt +++ b/test/conformance/CMakeLists.txt @@ -44,6 +44,23 @@ function(add_conformance_test_with_platform_environment name) target_compile_definitions("test-${name}" PRIVATE PLATFORM_ENVIRONMENT) endfunction() +function(add_fuzz_test name) + set(TEST_TARGET_NAME fuzztest-${name}) + add_executable(${TEST_TARGET_NAME} + ${ARGN}) + target_link_libraries(${TEST_TARGET_NAME} + PRIVATE + ${PROJECT_NAME}::loader + ${PROJECT_NAME}::headers + ${PROJECT_NAME}::common + -fsanitize=fuzzer) + add_test(NAME ${TEST_TARGET_NAME} + COMMAND ${TEST_TARGET_NAME} -max_total_time=10 -seed=1 -shrink=1 + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + set_tests_properties(${TEST_TARGET_NAME} PROPERTIES LABELS "fuzz") + target_compile_options(${TEST_TARGET_NAME} PRIVATE -g -fsanitize=fuzzer) +endfunction() + add_subdirectory(testing) add_subdirectory(platform) @@ -74,3 +91,7 @@ if(DEFINED UR_DPCXX) add_subdirectory(program) add_subdirectory(enqueue) endif() + +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + add_subdirectory(fuzz) +endif() diff --git a/test/conformance/fuzz/CMakeLists.txt b/test/conformance/fuzz/CMakeLists.txt new file mode 100644 index 0000000000..ab8af96776 --- /dev/null +++ b/test/conformance/fuzz/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (C) 2023 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 + +add_fuzz_test(conformance + urConformanceFuzz.cpp) diff --git a/test/conformance/fuzz/urConformanceFuzz.cpp b/test/conformance/fuzz/urConformanceFuzz.cpp new file mode 100644 index 0000000000..301452686d --- /dev/null +++ b/test/conformance/fuzz/urConformanceFuzz.cpp @@ -0,0 +1,126 @@ +// Copyright (C) 2023 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 +#include +#include + +#include "ur_api.h" + +extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { + enum FuncPtr { + UR_PLATFORM_GET, + UR_DEVICE_GET, + UR_CONTEXT_CREATE, + UR_USM_POOL_CREATE, + UR_USM_POOL_RELEASE, + UR_USM_HOST_ALLOC, + UR_USM_DEVICE_ALLOC, + UR_USM_FREE, + }; + + std::vector platforms; + std::vector devices; + std::map> pool_host_allocs; + std::vector no_pool_host_allocs; + ur_platform_handle_t platform = nullptr; + ur_context_handle_t context = nullptr; + constexpr ur_device_type_t device_type = UR_DEVICE_TYPE_ALL; + constexpr uint32_t num_entries = 5; + uint32_t num_platforms = 0; + uint32_t num_devices = 0; + + std::random_device rand_device; + std::mt19937 generator(rand_device()); + + ur_result_t ret = urInit(0); + if (ret != UR_RESULT_SUCCESS) { + return -1; + } + + uint8_t *data_ptr = data; + while (data_ptr != data + size) { + switch (*data_ptr++) { + case UR_PLATFORM_GET: + urPlatformGet(num_entries, platforms.data(), &num_platforms); + platforms.resize(num_platforms); + break; + case UR_DEVICE_GET: + if (!platforms.empty()) { + std::uniform_int_distribution distrib( + 0, platforms.size() - 1); + platform = platforms[distrib(generator)]; + } + urDeviceGet(platform, device_type, num_entries, devices.data(), + &num_devices); + devices.resize(num_devices); + break; + case UR_CONTEXT_CREATE: + if (!devices.empty()) { + urContextCreate(devices.size(), devices.data(), nullptr, + &context); + } + break; + case UR_USM_POOL_CREATE: + ur_usm_pool_handle_t pool; + urUSMPoolCreate(context, nullptr, &pool); + pool_host_allocs[pool] = {}; + break; + case UR_USM_POOL_RELEASE: + if (!pool_host_allocs.empty()) { + auto &[pool, allocs] = *pool_host_allocs.begin(); + if (!allocs.empty()) { + for (auto &ptr : allocs) { + urUSMFree(context, ptr); + } + } + urUSMPoolRelease(pool); + pool_host_allocs.erase(pool); + } + break; + case UR_USM_HOST_ALLOC: + void *ptr; + if (!pool_host_allocs.empty()) { + auto &[pool, allocs] = *pool_host_allocs.end(); + urUSMHostAlloc(context, nullptr, pool, 100, &ptr); + pool_host_allocs[pool].push_back(ptr); + } else { + urUSMHostAlloc(context, nullptr, nullptr, 100, &ptr); + no_pool_host_allocs.push_back(ptr); + } + break; + case UR_USM_FREE: + if (!no_pool_host_allocs.empty()) { + urUSMFree(context, no_pool_host_allocs.back()); + no_pool_host_allocs.pop_back(); + } else if (!pool_host_allocs.empty()) { + for (auto pool_it = pool_host_allocs.rbegin(); + pool_it != pool_host_allocs.rend(); ++pool_it) { + auto &[pool, allocs] = *pool_it; + if (!allocs.empty()) { + urUSMFree(context, allocs.back()); + allocs.pop_back(); + break; + } + } + } + break; + } + } + + for (const auto &[pool, allocs] : pool_host_allocs) { + for (auto &alloc : allocs) { + urUSMFree(context, alloc); + } + urUSMPoolRelease(pool); + } + for (auto &alloc : no_pool_host_allocs) { + urUSMFree(context, alloc); + } + for (auto &device : devices) { + urDeviceRelease(device); + } + urContextRelease(context); + return 0; +}