From b532350f3136676c9516287dc3389fafa9006dc9 Mon Sep 17 00:00:00 2001 From: "Wu, Yingcong" Date: Wed, 4 Dec 2024 11:03:00 +0100 Subject: [PATCH] [DevAsan] Report error when using unsupported extension API Some extensions are not currently supported by device address sanitizer. We may add support for those later, but for now, we will report errors when using unsupported API to let users know instead of failing for other random errors and puzzling the users. --- .../loader/layers/sanitizer/asan/asan_ddi.cpp | 223 ++++++++++++++++++ test/layers/sanitizer/asan.cpp | 63 +++++ 2 files changed, 286 insertions(+) diff --git a/source/loader/layers/sanitizer/asan/asan_ddi.cpp b/source/loader/layers/sanitizer/asan/asan_ddi.cpp index a823ceba2d..73415c1bcf 100644 --- a/source/loader/layers/sanitizer/asan/asan_ddi.cpp +++ b/source/loader/layers/sanitizer/asan/asan_ddi.cpp @@ -1554,6 +1554,52 @@ __urdlllocal ur_result_t UR_APICALL urKernelSetArgPointer( return result; } +/////////////////////////////////////////////////////////////////////////////// +/// @brief Intercept function for urDeviceGetInfo +__urdlllocal ur_result_t UR_APICALL urDeviceGetInfo( + ur_device_handle_t hDevice, ///< [in] handle of the device instance + ur_device_info_t propName, ///< [in] type of the info to retrieve + size_t propSize, ///< [in] the number of bytes pointed to by pPropValue. + void * + pPropValue, ///< [out][optional][typename(propName, propSize)] array of bytes holding + ///< the info. + ///< If propSize is not equal to or greater than the real number of bytes + ///< needed to return the info + ///< then the ::UR_RESULT_ERROR_INVALID_SIZE error is returned and + ///< pPropValue is not used. + size_t * + pPropSizeRet ///< [out][optional] pointer to the actual size in bytes of the queried propName. +) { + auto pfnGetInfo = getContext()->urDdiTable.Device.pfnGetInfo; + + if (nullptr == pfnGetInfo) { + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + + // For unsupported features for device address sanitizer, we override the result. + static std::unordered_set UnsupportedFeatures = { + // Virtual Memory + UR_DEVICE_INFO_VIRTUAL_MEMORY_SUPPORT, + + // Command Buffer + UR_DEVICE_INFO_COMMAND_BUFFER_SUPPORT_EXP, + UR_DEVICE_INFO_COMMAND_BUFFER_UPDATE_CAPABILITIES_EXP, + }; + if (UnsupportedFeatures.find(propName) != UnsupportedFeatures.end()) { + UrReturnHelper ReturnValue(propSize, pPropValue, pPropSizeRet); + + // handle non-bool return type queries + if (propName == UR_DEVICE_INFO_COMMAND_BUFFER_UPDATE_CAPABILITIES_EXP) { + ur_device_command_buffer_update_capability_flags_t flag = 0; + return ReturnValue(flag); + } + + return ReturnValue(false); + } + + return pfnGetInfo(hDevice, propName, propSize, pPropValue, pPropSizeRet); +} + /////////////////////////////////////////////////////////////////////////////// /// @brief Exported function for filling application's Global table /// with current process' addresses @@ -1843,6 +1889,168 @@ __urdlllocal ur_result_t UR_APICALL urGetUSMProcAddrTable( return result; } +/////////////////////////////////////////////////////////////////////////////// +/// @brief Exported function for filling application's Device 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 urGetDeviceProcAddrTable( + ur_api_version_t version, ///< [in] API version requested + ur_device_dditable_t + *pDdiTable ///< [in,out] pointer to table of DDI function pointers +) { + 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->pfnGetInfo = ur_sanitizer_layer::asan::urDeviceGetInfo; + + return result; +} + +template struct NotSupportedApi; + +template +struct NotSupportedApi { + R static ReportError(A...) { + getContext()->logger.error(MsgType::value); + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; + } +}; + +struct DevAsanNotSupportCommandBufferMsg { + static constexpr const char *value = + "CommandBuffer extension is not supported by UR_LAYER_ASAN"; +}; + +struct DevAsanNotSupportVirtualMemoryMsg { + static constexpr const char *value = + "VirtualMemory extension is not supported by UR_LAYER_ASAN"; +}; + +template +using CommandBufferNotSupported = + NotSupportedApi; + +template +using VirtualMemoryNotSupported = + NotSupportedApi; + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Exported function for filling application's CommandBufferExp 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 urGetCommandBufferExpProcAddrTable( + ur_api_version_t version, ///< [in] API version requested + ur_command_buffer_exp_dditable_t + *pDdiTable ///< [in,out] pointer to table of DDI function pointers +) { + 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; + +#define SET_UNSUPPORTED(FuncPtr) \ + do { \ + FuncPtr = CommandBufferNotSupported::ReportError; \ + } while (0) + + SET_UNSUPPORTED(pDdiTable->pfnCreateExp); + SET_UNSUPPORTED(pDdiTable->pfnRetainExp); + SET_UNSUPPORTED(pDdiTable->pfnReleaseExp); + SET_UNSUPPORTED(pDdiTable->pfnFinalizeExp); + SET_UNSUPPORTED(pDdiTable->pfnAppendKernelLaunchExp); + SET_UNSUPPORTED(pDdiTable->pfnAppendUSMFillExp); + SET_UNSUPPORTED(pDdiTable->pfnAppendMemBufferCopyExp); + SET_UNSUPPORTED(pDdiTable->pfnAppendMemBufferWriteExp); + SET_UNSUPPORTED(pDdiTable->pfnAppendMemBufferReadExp); + SET_UNSUPPORTED(pDdiTable->pfnAppendMemBufferCopyRectExp); + SET_UNSUPPORTED(pDdiTable->pfnAppendMemBufferWriteRectExp); + SET_UNSUPPORTED(pDdiTable->pfnAppendMemBufferReadRectExp); + SET_UNSUPPORTED(pDdiTable->pfnAppendMemBufferFillExp); + SET_UNSUPPORTED(pDdiTable->pfnAppendUSMPrefetchExp); + SET_UNSUPPORTED(pDdiTable->pfnAppendUSMAdviseExp); + SET_UNSUPPORTED(pDdiTable->pfnEnqueueExp); + SET_UNSUPPORTED(pDdiTable->pfnRetainCommandExp); + SET_UNSUPPORTED(pDdiTable->pfnReleaseCommandExp); + SET_UNSUPPORTED(pDdiTable->pfnUpdateKernelLaunchExp); + SET_UNSUPPORTED(pDdiTable->pfnUpdateSignalEventExp); + SET_UNSUPPORTED(pDdiTable->pfnUpdateWaitEventsExp); + SET_UNSUPPORTED(pDdiTable->pfnGetInfoExp); + SET_UNSUPPORTED(pDdiTable->pfnCommandGetInfoExp); + +#undef SET_UNSUPPORTED + + return result; +} + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Exported function for filling application's VirtualMem 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 urGetVirtualMemProcAddrTable( + ur_api_version_t version, ///< [in] API version requested + ur_virtual_mem_dditable_t + *pDdiTable ///< [in,out] pointer to table of DDI function pointers +) { + 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; + +#define SET_UNSUPPORTED(FuncPtr) \ + do { \ + FuncPtr = VirtualMemoryNotSupported::ReportError; \ + } while (0) + + SET_UNSUPPORTED(pDdiTable->pfnGranularityGetInfo); + SET_UNSUPPORTED(pDdiTable->pfnReserve); + SET_UNSUPPORTED(pDdiTable->pfnFree); + SET_UNSUPPORTED(pDdiTable->pfnMap); + SET_UNSUPPORTED(pDdiTable->pfnUnmap); + SET_UNSUPPORTED(pDdiTable->pfnSetAccess); + SET_UNSUPPORTED(pDdiTable->pfnGetInfo); + +#undef SET_UNSUPPORTED + + return result; +} } // namespace asan ur_result_t context_t::init(ur_dditable_t *dditable, @@ -1911,6 +2119,21 @@ ur_result_t context_t::init(ur_dditable_t *dditable, UR_API_VERSION_CURRENT, &dditable->USM); } + if (UR_RESULT_SUCCESS == result) { + result = ur_sanitizer_layer::asan::urGetDeviceProcAddrTable( + UR_API_VERSION_CURRENT, &dditable->Device); + } + + if (UR_RESULT_SUCCESS == result) { + result = ur_sanitizer_layer::asan::urGetCommandBufferExpProcAddrTable( + UR_API_VERSION_CURRENT, &dditable->CommandBufferExp); + } + + if (UR_RESULT_SUCCESS == result) { + result = ur_sanitizer_layer::asan::urGetVirtualMemProcAddrTable( + UR_API_VERSION_CURRENT, &dditable->VirtualMem); + } + return result; } diff --git a/test/layers/sanitizer/asan.cpp b/test/layers/sanitizer/asan.cpp index 0fbfe4cefe..02d368a9d0 100644 --- a/test/layers/sanitizer/asan.cpp +++ b/test/layers/sanitizer/asan.cpp @@ -56,3 +56,66 @@ TEST(DeviceAsan, Initialization) { status = urLoaderConfigRelease(loaderConfig); ASSERT_EQ(status, UR_RESULT_SUCCESS); } + +TEST(DeviceAsan, UnsupportedFeature) { + 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); + + // Check for explict unsupported features + ur_bool_t isSupported; + status = urDeviceGetInfo(device, UR_DEVICE_INFO_VIRTUAL_MEMORY_SUPPORT, + sizeof(isSupported), &isSupported, nullptr); + ASSERT_EQ(status, UR_RESULT_SUCCESS); + ASSERT_EQ(isSupported, 0); + + status = urDeviceGetInfo(device, UR_DEVICE_INFO_COMMAND_BUFFER_SUPPORT_EXP, + sizeof(isSupported), &isSupported, nullptr); + ASSERT_EQ(status, UR_RESULT_SUCCESS); + ASSERT_EQ(isSupported, 0); + + ur_device_command_buffer_update_capability_flags_t update_flag; + status = urDeviceGetInfo( + device, UR_DEVICE_INFO_COMMAND_BUFFER_UPDATE_CAPABILITIES_EXP, + sizeof(update_flag), &update_flag, nullptr); + ASSERT_EQ(status, UR_RESULT_SUCCESS); + ASSERT_EQ(update_flag, 0); + + status = urContextRelease(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); +}