From a99e798df36a898826e5cf29c6d197b24d6094c2 Mon Sep 17 00:00:00 2001 From: "Zhao, Maosu" Date: Mon, 23 Sep 2024 20:21:29 -0700 Subject: [PATCH 01/10] [DeviceSanitizer] Refactor the code to manage shadow memory --- source/loader/CMakeLists.txt | 4 +- .../layers/sanitizer/asan_interceptor.cpp | 271 ++++++------------ .../layers/sanitizer/asan_interceptor.hpp | 44 ++- .../loader/layers/sanitizer/asan_shadow.cpp | 232 +++++++++++++++ .../loader/layers/sanitizer/asan_shadow.hpp | 138 +++++++++ .../layers/sanitizer/asan_shadow_setup.cpp | 188 ------------ .../layers/sanitizer/asan_shadow_setup.hpp | 30 -- source/loader/layers/sanitizer/ur_sanddi.cpp | 132 ++++++++- .../layers/sanitizer/ur_sanitizer_utils.cpp | 13 +- .../layers/sanitizer/ur_sanitizer_utils.hpp | 6 + 10 files changed, 651 insertions(+), 407 deletions(-) create mode 100644 source/loader/layers/sanitizer/asan_shadow.cpp create mode 100644 source/loader/layers/sanitizer/asan_shadow.hpp delete mode 100644 source/loader/layers/sanitizer/asan_shadow_setup.cpp delete mode 100644 source/loader/layers/sanitizer/asan_shadow_setup.hpp diff --git a/source/loader/CMakeLists.txt b/source/loader/CMakeLists.txt index 48329cfb37..db79e49c59 100644 --- a/source/loader/CMakeLists.txt +++ b/source/loader/CMakeLists.txt @@ -148,8 +148,8 @@ if(UR_ENABLE_SANITIZER) ${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer/asan_quarantine.hpp ${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer/asan_report.cpp ${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer/asan_report.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer/asan_shadow_setup.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer/asan_shadow_setup.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer/asan_shadow.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer/asan_shadow.hpp ${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer/asan_validator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer/asan_validator.hpp ${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer/common.hpp diff --git a/source/loader/layers/sanitizer/asan_interceptor.cpp b/source/loader/layers/sanitizer/asan_interceptor.cpp index c4b8986b58..f8c7272e27 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.cpp +++ b/source/loader/layers/sanitizer/asan_interceptor.cpp @@ -15,164 +15,13 @@ #include "asan_options.hpp" #include "asan_quarantine.hpp" #include "asan_report.hpp" -#include "asan_shadow_setup.hpp" +#include "asan_shadow.hpp" #include "asan_validator.hpp" #include "stacktrace.hpp" #include "ur_sanitizer_utils.hpp" namespace ur_sanitizer_layer { -namespace { - -uptr MemToShadow_CPU(uptr USM_SHADOW_BASE, uptr UPtr) { - return USM_SHADOW_BASE + (UPtr >> ASAN_SHADOW_SCALE); -} - -uptr MemToShadow_DG2(uptr USM_SHADOW_BASE, uptr UPtr) { - if (UPtr & 0xFFFF000000000000ULL) { // Device USM - return USM_SHADOW_BASE + 0x80000000000ULL + - ((UPtr & 0x7FFFFFFFFFFFULL) >> ASAN_SHADOW_SCALE); - } else { // Host/Shared USM - return USM_SHADOW_BASE + (UPtr >> ASAN_SHADOW_SCALE); - } -} - -uptr MemToShadow_PVC(uptr USM_SHADOW_BASE, uptr UPtr) { - if (UPtr & 0xFF00000000000000ULL) { // Device USM - return USM_SHADOW_BASE + 0x80000000000ULL + - ((UPtr & 0xFFFFFFFFFFFFULL) >> ASAN_SHADOW_SCALE); - } else { // Only consider 47bit VA - return USM_SHADOW_BASE + - ((UPtr & 0x7FFFFFFFFFFFULL) >> ASAN_SHADOW_SCALE); - } -} - -ur_result_t urEnqueueUSMSet(ur_queue_handle_t Queue, void *Ptr, char Value, - size_t Size, uint32_t NumEvents = 0, - const ur_event_handle_t *EventWaitList = nullptr, - ur_event_handle_t *OutEvent = nullptr) { - if (Size == 0) { - return UR_RESULT_SUCCESS; - } - return getContext()->urDdiTable.Enqueue.pfnUSMFill( - Queue, Ptr, 1, &Value, Size, NumEvents, EventWaitList, OutEvent); -} - -ur_result_t enqueueMemSetShadow(ur_context_handle_t Context, - std::shared_ptr &DeviceInfo, - ur_queue_handle_t Queue, uptr Ptr, uptr Size, - u8 Value) { - if (Size == 0) { - return UR_RESULT_SUCCESS; - } - if (DeviceInfo->Type == DeviceType::CPU) { - /// - /// CPU Device: CPU needs to use a special memset function - /// - uptr ShadowBegin = MemToShadow_CPU(DeviceInfo->ShadowOffset, Ptr); - uptr ShadowEnd = - MemToShadow_CPU(DeviceInfo->ShadowOffset, Ptr + Size - 1); - - // Poison shadow memory outside of asan runtime is not allowed, so we - // need to avoid memset's call from being intercepted. - static auto MemSet = - (void *(*)(void *, int, size_t))GetMemFunctionPointer("memset"); - if (!MemSet) { - return UR_RESULT_ERROR_UNKNOWN; - } - getContext()->logger.debug( - "enqueueMemSetShadow(addr={}, count={}, value={})", - (void *)ShadowBegin, ShadowEnd - ShadowBegin + 1, - (void *)(size_t)Value); - MemSet((void *)ShadowBegin, Value, ShadowEnd - ShadowBegin + 1); - } else { - /// - /// GPU Device: GPU needs to manually map physical memory before memset - /// - uptr ShadowBegin = 0, ShadowEnd = 0; - - if (DeviceInfo->Type == DeviceType::GPU_PVC) { - ShadowBegin = MemToShadow_PVC(DeviceInfo->ShadowOffset, Ptr); - ShadowEnd = - MemToShadow_PVC(DeviceInfo->ShadowOffset, Ptr + Size - 1); - } else if (DeviceInfo->Type == DeviceType::GPU_DG2) { - ShadowBegin = MemToShadow_DG2(DeviceInfo->ShadowOffset, Ptr); - ShadowEnd = - MemToShadow_DG2(DeviceInfo->ShadowOffset, Ptr + Size - 1); - } else { - getContext()->logger.error("Unsupport device type"); - return UR_RESULT_ERROR_INVALID_ARGUMENT; - } - - assert(ShadowBegin <= ShadowEnd); - { - static const size_t PageSize = - GetVirtualMemGranularity(Context, DeviceInfo->Handle); - - ur_physical_mem_properties_t Desc{ - UR_STRUCTURE_TYPE_PHYSICAL_MEM_PROPERTIES, nullptr, 0}; - static ur_physical_mem_handle_t PhysicalMem{}; - - // Make sure [Ptr, Ptr + Size] is mapped to physical memory - for (auto MappedPtr = RoundDownTo(ShadowBegin, PageSize); - MappedPtr <= ShadowEnd; MappedPtr += PageSize) { - if (!PhysicalMem) { - auto URes = getContext()->urDdiTable.PhysicalMem.pfnCreate( - Context, DeviceInfo->Handle, PageSize, &Desc, - &PhysicalMem); - if (URes != UR_RESULT_SUCCESS) { - getContext()->logger.error("urPhysicalMemCreate(): {}", - URes); - return URes; - } - } - - getContext()->logger.debug("urVirtualMemMap: {} ~ {}", - (void *)MappedPtr, - (void *)(MappedPtr + PageSize - 1)); - - // FIXME: No flag to check the failed reason is VA is already mapped - auto URes = getContext()->urDdiTable.VirtualMem.pfnMap( - Context, (void *)MappedPtr, PageSize, PhysicalMem, 0, - UR_VIRTUAL_MEM_ACCESS_FLAG_READ_WRITE); - if (URes != UR_RESULT_SUCCESS) { - getContext()->logger.debug("urVirtualMemMap({}, {}): {}", - (void *)MappedPtr, PageSize, - URes); - } - - // Initialize to zero - if (URes == UR_RESULT_SUCCESS) { - // Reset PhysicalMem to null since it's been mapped - PhysicalMem = nullptr; - - auto URes = - urEnqueueUSMSet(Queue, (void *)MappedPtr, 0, PageSize); - if (URes != UR_RESULT_SUCCESS) { - getContext()->logger.error("urEnqueueUSMFill(): {}", - URes); - return URes; - } - } - } - } - - auto URes = urEnqueueUSMSet(Queue, (void *)ShadowBegin, Value, - ShadowEnd - ShadowBegin + 1); - getContext()->logger.debug( - "enqueueMemSetShadow (addr={}, count={}, value={}): {}", - (void *)ShadowBegin, ShadowEnd - ShadowBegin + 1, - (void *)(size_t)Value, URes); - if (URes != UR_RESULT_SUCCESS) { - getContext()->logger.error("urEnqueueUSMFill(): {}", URes); - return URes; - } - } - return UR_RESULT_SUCCESS; -} - -} // namespace - SanitizerInterceptor::SanitizerInterceptor(logger::Logger &logger) : logger(logger) { if (Options(logger).MaxQuarantineSizeMB) { @@ -183,9 +32,9 @@ SanitizerInterceptor::SanitizerInterceptor(logger::Logger &logger) } SanitizerInterceptor::~SanitizerInterceptor() { - DestroyShadowMemoryOnCPU(); - DestroyShadowMemoryOnPVC(); - DestroyShadowMemoryOnDG2(); + for (const auto &[_, DeviceInfo] : m_DeviceMap) { + DeviceInfo->Shadow->Destory(); + } // We must release these objects before releasing adapters, since // they may use the adapter in their destructor @@ -349,6 +198,15 @@ ur_result_t SanitizerInterceptor::releaseMemory(ur_context_handle_t Context, getContext()->logger.debug("Free: {}", (void *)AllocInfo->AllocBegin); std::scoped_lock Guard(m_AllocationMapMutex); m_AllocationMap.erase(AllocInfoIt); + if (AllocInfo->Type == AllocType::HOST_USM) { + for (auto &Device : ContextInfo->DeviceList) { + UR_CALL( + getDeviceInfo(Device)->Shadow->ReleaseShadow(AllocInfo)); + } + } else { + UR_CALL(getDeviceInfo(AllocInfo->Device) + ->Shadow->ReleaseShadow(AllocInfo)); + } return getContext()->urDdiTable.USM.pfnFree( Context, (void *)(AllocInfo->AllocBegin)); } @@ -360,6 +218,15 @@ ur_result_t SanitizerInterceptor::releaseMemory(ur_context_handle_t Context, getContext()->logger.info("Quarantine Free: {}", (void *)It->second->AllocBegin); m_AllocationMap.erase(It); + if (AllocInfo->Type == AllocType::HOST_USM) { + for (auto &Device : ContextInfo->DeviceList) { + UR_CALL(getDeviceInfo(Device)->Shadow->ReleaseShadow( + AllocInfo)); + } + } else { + UR_CALL(getDeviceInfo(AllocInfo->Device) + ->Shadow->ReleaseShadow(AllocInfo)); + } UR_CALL(getContext()->urDdiTable.USM.pfnFree( Context, (void *)(It->second->AllocBegin))); } @@ -427,24 +294,25 @@ ur_result_t SanitizerInterceptor::postLaunchKernel(ur_kernel_handle_t Kernel, ur_result_t DeviceInfo::allocShadowMemory(ur_context_handle_t Context) { if (Type == DeviceType::CPU) { - UR_CALL(SetupShadowMemoryOnCPU(ShadowOffset, ShadowOffsetEnd)); + Shadow = std::make_unique(Context, Handle); } else if (Type == DeviceType::GPU_PVC) { - UR_CALL(SetupShadowMemoryOnPVC(Context, ShadowOffset, ShadowOffsetEnd)); + Shadow = std::make_unique(Context, Handle); } else if (Type == DeviceType::GPU_DG2) { - UR_CALL(SetupShadowMemoryOnDG2(Context, ShadowOffset, ShadowOffsetEnd)); + Shadow = std::make_unique(Context, Handle); } else { getContext()->logger.error("Unsupport device type"); return UR_RESULT_ERROR_INVALID_ARGUMENT; } + UR_CALL(Shadow->Setup()); getContext()->logger.info("ShadowMemory(Global): {} - {}", - (void *)ShadowOffset, (void *)ShadowOffsetEnd); + (void *)Shadow->ShadowBegin, + (void *)Shadow->ShadowEnd); // Set shadow memory for null pointer ManagedQueue Queue(Context, Handle); - auto DI = getContext()->interceptor->getDeviceInfo(Handle); auto URes = - enqueueMemSetShadow(Context, DI, Queue, 0, 1, kNullPointerRedzoneMagic); + Shadow->EnqueuePoisonShadow(Queue, 0, 1, kNullPointerRedzoneMagic); if (URes != UR_RESULT_SUCCESS) { getContext()->logger.error("enqueueMemSetShadow(NullPointerRZ): {}", URes); @@ -460,9 +328,10 @@ ur_result_t DeviceInfo::allocShadowMemory(ur_context_handle_t Context) { /// - 1 <= k <= 7: Only the first k bytes is accessible /// /// ref: https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm#mapping -ur_result_t SanitizerInterceptor::enqueueAllocInfo( - ur_context_handle_t Context, std::shared_ptr &DeviceInfo, - ur_queue_handle_t Queue, std::shared_ptr &AI) { +ur_result_t +SanitizerInterceptor::enqueueAllocInfo(std::shared_ptr &DeviceInfo, + ur_queue_handle_t Queue, + std::shared_ptr &AI) { if (AI->IsReleased) { int ShadowByte; switch (AI->Type) { @@ -482,14 +351,14 @@ ur_result_t SanitizerInterceptor::enqueueAllocInfo( ShadowByte = 0xff; assert(false && "Unknow AllocInfo Type"); } - UR_CALL(enqueueMemSetShadow(Context, DeviceInfo, Queue, AI->AllocBegin, - AI->AllocSize, ShadowByte)); + UR_CALL(DeviceInfo->Shadow->EnqueuePoisonShadow( + Queue, AI->AllocBegin, AI->AllocSize, ShadowByte)); return UR_RESULT_SUCCESS; } // Init zero - UR_CALL(enqueueMemSetShadow(Context, DeviceInfo, Queue, AI->AllocBegin, - AI->AllocSize, 0)); + UR_CALL(DeviceInfo->Shadow->EnqueuePoisonShadow(Queue, AI->AllocBegin, + AI->AllocSize, 0)); uptr TailBegin = RoundUpTo(AI->UserEnd, ASAN_SHADOW_GRANULARITY); uptr TailEnd = AI->AllocBegin + AI->AllocSize; @@ -498,8 +367,8 @@ ur_result_t SanitizerInterceptor::enqueueAllocInfo( if (TailBegin != AI->UserEnd) { auto Value = AI->UserEnd - RoundDownTo(AI->UserEnd, ASAN_SHADOW_GRANULARITY); - UR_CALL(enqueueMemSetShadow(Context, DeviceInfo, Queue, AI->UserEnd, 1, - static_cast(Value))); + UR_CALL(DeviceInfo->Shadow->EnqueuePoisonShadow( + Queue, AI->UserEnd, 1, static_cast(Value))); } int ShadowByte; @@ -525,12 +394,12 @@ ur_result_t SanitizerInterceptor::enqueueAllocInfo( } // Left red zone - UR_CALL(enqueueMemSetShadow(Context, DeviceInfo, Queue, AI->AllocBegin, - AI->UserBegin - AI->AllocBegin, ShadowByte)); + UR_CALL(DeviceInfo->Shadow->EnqueuePoisonShadow( + Queue, AI->AllocBegin, AI->UserBegin - AI->AllocBegin, ShadowByte)); // Right red zone - UR_CALL(enqueueMemSetShadow(Context, DeviceInfo, Queue, TailBegin, - TailEnd - TailBegin, ShadowByte)); + UR_CALL(DeviceInfo->Shadow->EnqueuePoisonShadow( + Queue, TailBegin, TailEnd - TailBegin, ShadowByte)); return UR_RESULT_SUCCESS; } @@ -542,7 +411,7 @@ ur_result_t SanitizerInterceptor::updateShadowMemory( std::scoped_lock Guard(AllocInfos.Mutex); for (auto &AI : AllocInfos.List) { - UR_CALL(enqueueAllocInfo(ContextInfo->Handle, DeviceInfo, Queue, AI)); + UR_CALL(enqueueAllocInfo(DeviceInfo, Queue, AI)); } AllocInfos.List.clear(); @@ -555,6 +424,7 @@ SanitizerInterceptor::registerDeviceGlobals(ur_context_handle_t Context, std::vector Devices = GetProgramDevices(Program); auto ContextInfo = getContextInfo(Context); + auto ProgramInfo = getProgramInfo(Program); for (auto Device : Devices) { ManagedQueue Queue(Context, Device); @@ -596,12 +466,34 @@ SanitizerInterceptor::registerDeviceGlobals(ur_context_handle_t Context, {}}); ContextInfo->insertAllocInfo({Device}, AI); + + { + std::scoped_lock Guard( + m_AllocationMapMutex, ProgramInfo->Mutex); + ProgramInfo->AllocInfoForGlobals.emplace(AI); + m_AllocationMap.emplace(AI->AllocBegin, std::move(AI)); + } } } return UR_RESULT_SUCCESS; } +ur_result_t +SanitizerInterceptor::unregisterDeviceGlobals(ur_program_handle_t Program) { + auto ProgramInfo = getProgramInfo(Program); + + std::scoped_lock Guard( + m_AllocationMapMutex, ProgramInfo->Mutex); + for (auto AI : ProgramInfo->AllocInfoForGlobals) { + UR_CALL(getDeviceInfo(AI->Device)->Shadow->ReleaseShadow(AI)); + m_AllocationMap.erase(AI->AllocBegin); + } + ProgramInfo->AllocInfoForGlobals.clear(); + + return UR_RESULT_SUCCESS; +} + ur_result_t SanitizerInterceptor::insertContext(ur_context_handle_t Context, std::shared_ptr &CI) { @@ -662,6 +554,22 @@ ur_result_t SanitizerInterceptor::eraseDevice(ur_device_handle_t Device) { return UR_RESULT_SUCCESS; } +ur_result_t SanitizerInterceptor::insertProgram(ur_program_handle_t Program) { + std::scoped_lock Guard(m_ProgramMapMutex); + if (m_ProgramMap.find(Program) != m_ProgramMap.end()) { + return UR_RESULT_SUCCESS; + } + m_ProgramMap.emplace(Program, std::make_shared(Program)); + return UR_RESULT_SUCCESS; +} + +ur_result_t SanitizerInterceptor::eraseProgram(ur_program_handle_t Program) { + std::scoped_lock Guard(m_ProgramMapMutex); + assert(m_ProgramMap.find(Program) != m_ProgramMap.end()); + m_ProgramMap.erase(Program); + return UR_RESULT_SUCCESS; +} + ur_result_t SanitizerInterceptor::insertKernel(ur_kernel_handle_t Kernel) { std::scoped_lock Guard(m_KernelMapMutex); if (m_KernelMap.find(Kernel) != m_KernelMap.end()) { @@ -784,11 +692,11 @@ ur_result_t SanitizerInterceptor::prepareLaunch( // Write shadow memory offset for global memory EnqueueWriteGlobal(kSPIR_AsanShadowMemoryGlobalStart, - &DeviceInfo->ShadowOffset, - sizeof(DeviceInfo->ShadowOffset)); + &DeviceInfo->Shadow->ShadowBegin, + sizeof(DeviceInfo->Shadow->ShadowBegin)); EnqueueWriteGlobal(kSPIR_AsanShadowMemoryGlobalEnd, - &DeviceInfo->ShadowOffsetEnd, - sizeof(DeviceInfo->ShadowOffsetEnd)); + &DeviceInfo->Shadow->ShadowEnd, + sizeof(DeviceInfo->Shadow->ShadowEnd)); // Write device type EnqueueWriteGlobal(kSPIR_DeviceType, &DeviceInfo->Type, @@ -830,7 +738,7 @@ ur_result_t SanitizerInterceptor::prepareLaunch( return URes; } // Initialize shadow memory - URes = urEnqueueUSMSet(Queue, Allocated, 0, Size); + URes = EnqueueUSMBlockingSet(Queue, Allocated, 0, Size); if (URes != UR_RESULT_SUCCESS) { [[maybe_unused]] auto URes = getContext()->urDdiTable.USM.pfnFree(Context, Allocated); @@ -894,7 +802,8 @@ ur_result_t SanitizerInterceptor::prepareLaunch( // Write shadow memory offset for private memory if (Options(logger).DetectPrivates) { if (DeviceInfo->Type == DeviceType::CPU) { - LaunchInfo.Data->PrivateShadowOffset = DeviceInfo->ShadowOffset; + LaunchInfo.Data->PrivateShadowOffset = + DeviceInfo->Shadow->ShadowBegin; } else if (DeviceInfo->Type == DeviceType::GPU_PVC || DeviceInfo->Type == DeviceType::GPU_DG2) { const size_t PrivateShadowMemorySize = diff --git a/source/loader/layers/sanitizer/asan_interceptor.hpp b/source/loader/layers/sanitizer/asan_interceptor.hpp index 271669d60e..262d6ca20c 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.hpp +++ b/source/loader/layers/sanitizer/asan_interceptor.hpp @@ -15,6 +15,7 @@ #include "asan_allocator.hpp" #include "asan_buffer.hpp" #include "asan_libdevice.hpp" +#include "asan_shadow.hpp" #include "common.hpp" #include "ur_sanitizer_layer.hpp" @@ -39,8 +40,7 @@ struct DeviceInfo { DeviceType Type = DeviceType::UNKNOWN; size_t Alignment = 0; - uptr ShadowOffset = 0; - uptr ShadowOffsetEnd = 0; + std::unique_ptr Shadow; // Device features bool IsSupportSharedSystemUSM = false; @@ -104,6 +104,27 @@ struct KernelInfo { } }; +struct ProgramInfo { + ur_program_handle_t Handle; + std::atomic RefCount = 1; + + // lock this mutex if following fields are accessed + ur_shared_mutex Mutex; + std::unordered_set> AllocInfoForGlobals; + + explicit ProgramInfo(ur_program_handle_t Program) : Handle(Program) { + [[maybe_unused]] auto Result = + getContext()->urDdiTable.Program.pfnRetain(Handle); + assert(Result == UR_RESULT_SUCCESS); + } + + ~ProgramInfo() { + [[maybe_unused]] auto Result = + getContext()->urDdiTable.Program.pfnRelease(Handle); + assert(Result == UR_RESULT_SUCCESS); + } +}; + struct ContextInfo { ur_context_handle_t Handle; std::atomic RefCount = 1; @@ -177,6 +198,8 @@ class SanitizerInterceptor { ur_result_t registerDeviceGlobals(ur_context_handle_t Context, ur_program_handle_t Program); + ur_result_t unregisterDeviceGlobals(ur_program_handle_t Program); + ur_result_t preLaunchKernel(ur_kernel_handle_t Kernel, ur_queue_handle_t Queue, USMLaunchInfo &LaunchInfo); @@ -193,6 +216,9 @@ class SanitizerInterceptor { std::shared_ptr &CI); ur_result_t eraseDevice(ur_device_handle_t Device); + ur_result_t insertProgram(ur_program_handle_t Program); + ur_result_t eraseProgram(ur_program_handle_t Program); + ur_result_t insertKernel(ur_kernel_handle_t Kernel); ur_result_t eraseKernel(ur_kernel_handle_t Kernel); @@ -227,6 +253,12 @@ class SanitizerInterceptor { return m_DeviceMap[Device]; } + std::shared_ptr getProgramInfo(ur_program_handle_t Program) { + std::shared_lock Guard(m_ProgramMapMutex); + assert(m_ProgramMap.find(Program) != m_ProgramMap.end()); + return m_ProgramMap[Program]; + } + std::shared_ptr getKernelInfo(ur_kernel_handle_t Kernel) { std::shared_lock Guard(m_KernelMapMutex); assert(m_KernelMap.find(Kernel) != m_KernelMap.end()); @@ -237,8 +269,8 @@ class SanitizerInterceptor { ur_result_t updateShadowMemory(std::shared_ptr &ContextInfo, std::shared_ptr &DeviceInfo, ur_queue_handle_t Queue); - ur_result_t enqueueAllocInfo(ur_context_handle_t Context, - std::shared_ptr &DeviceInfo, + + ur_result_t enqueueAllocInfo(std::shared_ptr &DeviceInfo, ur_queue_handle_t Queue, std::shared_ptr &AI); @@ -260,6 +292,10 @@ class SanitizerInterceptor { m_DeviceMap; ur_shared_mutex m_DeviceMapMutex; + std::unordered_map> + m_ProgramMap; + ur_shared_mutex m_ProgramMapMutex; + std::unordered_map> m_KernelMap; ur_shared_mutex m_KernelMapMutex; diff --git a/source/loader/layers/sanitizer/asan_shadow.cpp b/source/loader/layers/sanitizer/asan_shadow.cpp new file mode 100644 index 0000000000..1a4d7f546c --- /dev/null +++ b/source/loader/layers/sanitizer/asan_shadow.cpp @@ -0,0 +1,232 @@ +/* + * + * 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 asan_shadow.cpp + * + */ + +#include "asan_shadow.hpp" +#include "asan_interceptor.hpp" +#include "asan_libdevice.hpp" +#include "ur_sanitizer_layer.hpp" +#include "ur_sanitizer_utils.hpp" + +namespace ur_sanitizer_layer { + +ur_result_t ShadowMemoryCPU::Setup() { + static ur_result_t Result = [this]() { + size_t ShadowSize = GetShadowSize(); + ShadowBegin = MmapNoReserve(0, ShadowSize); + if (ShadowBegin == 0) { + return UR_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + DontCoredumpRange(ShadowBegin, ShadowSize); + ShadowEnd = ShadowBegin + ShadowSize; + IsShadowMemInited = true; + return UR_RESULT_SUCCESS; + }(); + return Result; +} + +ur_result_t ShadowMemoryCPU::Destory() { + if (!IsShadowMemInited) { + return UR_RESULT_SUCCESS; + } + static ur_result_t Result = [this]() { + if (!Munmap(ShadowBegin, GetShadowSize())) { + return UR_RESULT_ERROR_UNKNOWN; + } + return UR_RESULT_SUCCESS; + }(); + return Result; +} + +uptr ShadowMemoryCPU::MemToShadow(uptr Ptr) { + return ShadowBegin + (Ptr >> ASAN_SHADOW_SCALE); +} + +ur_result_t ShadowMemoryCPU::EnqueuePoisonShadow(ur_queue_handle_t, uptr Ptr, + uptr Size, u8 Value) { + if (Size == 0) { + return UR_RESULT_SUCCESS; + } + + uptr ShadowBegin = MemToShadow(Ptr); + uptr ShadowEnd = MemToShadow(Ptr + Size - 1); + assert(ShadowBegin <= ShadowEnd); + getContext()->logger.debug( + "EnqueuePoisonShadow(addr={}, count={}, value={})", (void *)ShadowBegin, + ShadowEnd - ShadowBegin + 1, (void *)(size_t)Value); + memset((void *)ShadowBegin, Value, ShadowEnd - ShadowBegin + 1); + + return UR_RESULT_SUCCESS; +} + +ur_result_t ShadowMemoryGPU::Setup() { + // Currently, Level-Zero doesn't create independent VAs for each contexts, if we reserve + // shadow memory for each contexts, this will cause out-of-resource error when user uses + // multiple contexts. Therefore, we just create one shadow memory here. + static ur_result_t Result = [this]() { + size_t ShadowSize = GetShadowSize(); + // TODO: Protect Bad Zone + auto Result = getContext()->urDdiTable.VirtualMem.pfnReserve( + Context, nullptr, ShadowSize, (void **)&ShadowBegin); + if (Result == UR_RESULT_SUCCESS) { + ShadowEnd = ShadowBegin + ShadowSize; + // Retain the context which reserves shadow memory + getContext()->urDdiTable.Context.pfnRetain(Context); + } + IsShadowMemInited = true; + return Result; + }(); + return Result; +} + +ur_result_t ShadowMemoryGPU::Destory() { + if (!IsShadowMemInited) { + return UR_RESULT_SUCCESS; + } + static ur_result_t Result = [this]() { + auto Result = getContext()->urDdiTable.VirtualMem.pfnFree( + Context, (const void *)ShadowBegin, GetShadowSize()); + getContext()->urDdiTable.Context.pfnRelease(Context); + return Result; + }(); + return Result; +} + +ur_result_t ShadowMemoryGPU::EnqueuePoisonShadow(ur_queue_handle_t Queue, + uptr Ptr, uptr Size, + u8 Value) { + if (Size == 0) { + return UR_RESULT_SUCCESS; + } + + uptr ShadowBegin = MemToShadow(Ptr); + uptr ShadowEnd = MemToShadow(Ptr + Size - 1); + assert(ShadowBegin <= ShadowEnd); + { + static const size_t PageSize = + GetVirtualMemGranularity(Context, Device); + + ur_physical_mem_properties_t Desc{ + UR_STRUCTURE_TYPE_PHYSICAL_MEM_PROPERTIES, nullptr, 0}; + + // Make sure [Ptr, Ptr + Size] is mapped to physical memory + for (auto MappedPtr = RoundDownTo(ShadowBegin, PageSize); + MappedPtr <= ShadowEnd; MappedPtr += PageSize) { + std::scoped_lock Guard(VirtualMemMapsMutex); + if (VirtualMemMaps.find(MappedPtr) == VirtualMemMaps.end()) { + ur_physical_mem_handle_t PhysicalMem{}; + auto URes = getContext()->urDdiTable.PhysicalMem.pfnCreate( + Context, Device, PageSize, &Desc, &PhysicalMem); + if (URes != UR_RESULT_SUCCESS) { + getContext()->logger.error("urPhysicalMemCreate(): {}", + URes); + return URes; + } + + URes = getContext()->urDdiTable.VirtualMem.pfnMap( + Context, (void *)MappedPtr, PageSize, PhysicalMem, 0, + UR_VIRTUAL_MEM_ACCESS_FLAG_READ_WRITE); + if (URes != UR_RESULT_SUCCESS) { + getContext()->logger.debug("urVirtualMemMap({}, {}): {}", + (void *)MappedPtr, PageSize, + URes); + return URes; + } + + getContext()->logger.debug("urVirtualMemMap: {} ~ {}", + (void *)MappedPtr, + (void *)(MappedPtr + PageSize - 1)); + + // Initialize to zero + URes = EnqueueUSMBlockingSet(Queue, (void *)MappedPtr, 0, + PageSize); + if (URes != UR_RESULT_SUCCESS) { + getContext()->logger.error("EnqueueUSMBlockingSet(): {}", + URes); + return URes; + } + + VirtualMemMaps[MappedPtr].first = PhysicalMem; + } + + // We don't need to record virtual memory map for null pointer. + if (Ptr == 0) { + continue; + } + + auto AllocInfoIt = + getContext()->interceptor->findAllocInfoByAddress(Ptr); + assert(AllocInfoIt); + VirtualMemMaps[MappedPtr].second.insert((*AllocInfoIt)->second); + } + } + + auto URes = EnqueueUSMBlockingSet(Queue, (void *)ShadowBegin, Value, + ShadowEnd - ShadowBegin + 1); + getContext()->logger.debug( + "EnqueuePoisonShadow (addr={}, count={}, value={}): {}", + (void *)ShadowBegin, ShadowEnd - ShadowBegin + 1, (void *)(size_t)Value, + URes); + if (URes != UR_RESULT_SUCCESS) { + getContext()->logger.error("EnqueueUSMBlockingSet(): {}", URes); + return URes; + } + + return UR_RESULT_SUCCESS; +} + +ur_result_t ShadowMemoryGPU::ReleaseShadow(std::shared_ptr AI) { + uptr ShadowBegin = MemToShadow(AI->AllocBegin); + uptr ShadowEnd = MemToShadow(AI->AllocBegin + AI->AllocSize); + assert(ShadowBegin <= ShadowEnd); + + static const size_t PageSize = GetVirtualMemGranularity(Context, Device); + + for (auto MappedPtr = RoundDownTo(ShadowBegin, PageSize); + MappedPtr <= ShadowEnd; MappedPtr += PageSize) { + std::scoped_lock Guard(VirtualMemMapsMutex); + if (VirtualMemMaps.find(MappedPtr) == VirtualMemMaps.end()) { + continue; + } + VirtualMemMaps[MappedPtr].second.erase(AI); + if (VirtualMemMaps[MappedPtr].second.empty()) { + UR_CALL(getContext()->urDdiTable.VirtualMem.pfnUnmap( + Context, (void *)MappedPtr, PageSize)); + UR_CALL(getContext()->urDdiTable.PhysicalMem.pfnRelease( + VirtualMemMaps[MappedPtr].first)); + getContext()->logger.debug("urVirtualMemUnmap: {} ~ {}", + (void *)MappedPtr, + (void *)(MappedPtr + PageSize - 1)); + } + } + + return UR_RESULT_SUCCESS; +} + +uptr ShadowMemoryPVC::MemToShadow(uptr Ptr) { + if (Ptr & 0xFF00000000000000ULL) { // Device USM + return ShadowBegin + 0x80000000000ULL + + ((Ptr & 0xFFFFFFFFFFFFULL) >> ASAN_SHADOW_SCALE); + } else { // Only consider 47bit VA + return ShadowBegin + ((Ptr & 0x7FFFFFFFFFFFULL) >> ASAN_SHADOW_SCALE); + } +} + +uptr ShadowMemoryDG2::MemToShadow(uptr Ptr) { + if (Ptr & 0xFFFF000000000000ULL) { // Device USM + return ShadowBegin + 0x80000000000ULL + + ((Ptr & 0x7FFFFFFFFFFFULL) >> ASAN_SHADOW_SCALE); + } else { // Host/Shared USM + return ShadowBegin + (Ptr >> ASAN_SHADOW_SCALE); + } +} + +} // namespace ur_sanitizer_layer diff --git a/source/loader/layers/sanitizer/asan_shadow.hpp b/source/loader/layers/sanitizer/asan_shadow.hpp new file mode 100644 index 0000000000..5cd4878f0f --- /dev/null +++ b/source/loader/layers/sanitizer/asan_shadow.hpp @@ -0,0 +1,138 @@ +/* + * + * 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 asan_shadow.hpp + * + */ + +#pragma once + +#include "common.hpp" +#include "asan_allocator.hpp" +#include + +namespace ur_sanitizer_layer { + +struct ShadowMemory { + ShadowMemory(ur_context_handle_t Context, ur_device_handle_t Device) + : Context(Context), Device(Device) {} + + virtual ur_result_t Setup() = 0; + + virtual ur_result_t Destory() = 0; + + virtual uptr MemToShadow(uptr Ptr) = 0; + + virtual ur_result_t EnqueuePoisonShadow(ur_queue_handle_t Queue, uptr Ptr, + uptr Size, u8 Value) = 0; + + virtual ur_result_t ReleaseShadow(std::shared_ptr) { + return UR_RESULT_SUCCESS; + } + + virtual size_t GetShadowSize() = 0; + + ur_context_handle_t Context{}; + + ur_device_handle_t Device{}; + + uptr ShadowBegin = 0; + + uptr ShadowEnd = 0; + + bool IsShadowMemInited = false; +}; + +struct ShadowMemoryCPU final : public ShadowMemory { + ShadowMemoryCPU(ur_context_handle_t Context, ur_device_handle_t Device) + : ShadowMemory(Context, Device) {} + + virtual ur_result_t Setup() override; + + virtual ur_result_t Destory() override; + + virtual uptr MemToShadow(uptr Ptr) override; + + virtual ur_result_t EnqueuePoisonShadow(ur_queue_handle_t Queue, uptr Ptr, + uptr Size, u8 Value) override; + + virtual size_t GetShadowSize() override { + return 0x80000000000ULL; + } +}; + +struct ShadowMemoryGPU : public ShadowMemory { + ShadowMemoryGPU(ur_context_handle_t Context, ur_device_handle_t Device) + : ShadowMemory(Context, Device) {} + + virtual ur_result_t Setup() override; + + virtual ur_result_t Destory() override; + virtual ur_result_t EnqueuePoisonShadow(ur_queue_handle_t Queue, uptr Ptr, + uptr Size, u8 Value) override final; + + virtual ur_result_t + ReleaseShadow(std::shared_ptr AI) override final; + + ur_mutex VirtualMemMapsMutex; + + std::unordered_map< + uptr, std::pair>>> + VirtualMemMaps; +}; + +/// Shadow Memory layout of GPU PVC device +/// +/// USM Allocation Range (56 bits) +/// Host USM : 0x0000_0000_0000_0000 ~ 0x00ff_ffff_ffff_ffff +/// Shared USM : 0x0000_0000_0000_0000 ~ 0x0000_7fff_ffff_ffff +/// Device USM : 0xff00_0000_0000_0000 ~ 0xff00_ffff_ffff_ffff +/// +/// USM Allocation Range (AllocateHostAllocationsInHeapExtendedHost=0) +/// Host USM : 0x0000_0000_0000_0000 ~ 0x0000_7fff_ffff_ffff +/// Shared USM : 0x0000_0000_0000_0000 ~ 0x0000_7fff_ffff_ffff +/// Device USM : 0xff00_0000_0000_0000 ~ 0xff00_ffff_ffff_ffff +/// +/// Shadow Memory Mapping (SHADOW_SCALE=4, AllocateHostAllocationsInHeapExtendedHost=0) +/// Host/Shared USM : 0x0 ~ 0x07ff_ffff_ffff +/// Device USM : 0x0800_0000_0000 ~ 0x17ff_ffff_ffff +/// +struct ShadowMemoryPVC final : public ShadowMemoryGPU { + ShadowMemoryPVC(ur_context_handle_t Context, ur_device_handle_t Device) + : ShadowMemoryGPU(Context, Device) {} + + virtual uptr MemToShadow(uptr Ptr) override; + + virtual size_t GetShadowSize() override { + return 0x180000000000ULL; + } +}; + +/// Shadow Memory layout of GPU PVC device +/// +/// USM Allocation Range (48 bits) +/// Host/Shared USM : 0x0000_0000_0000_0000 ~ 0x0000_7fff_ffff_ffff +/// Device USM : 0xffff_8000_0000_0000 ~ 0xffff_ffff_ffff_ffff +/// +/// Shadow Memory Mapping (SHADOW_SCALE=4) +/// Host/Shared USM : 0x0 ~ 0x07ff_ffff_ffff +/// Device USM : 0x0800_0000_0000 ~ 0x0fff_ffff_ffff +/// +struct ShadowMemoryDG2 final : public ShadowMemoryGPU { + ShadowMemoryDG2(ur_context_handle_t Context, ur_device_handle_t Device) + : ShadowMemoryGPU(Context, Device) {} + + virtual uptr MemToShadow(uptr Ptr) override; + + virtual size_t GetShadowSize() override { + return 0x100000000000ULL; + } +}; + +} // namespace ur_sanitizer_layer diff --git a/source/loader/layers/sanitizer/asan_shadow_setup.cpp b/source/loader/layers/sanitizer/asan_shadow_setup.cpp deleted file mode 100644 index f543c9146e..0000000000 --- a/source/loader/layers/sanitizer/asan_shadow_setup.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/* - * - * 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 asan_shadow_setup.cpp - * - */ - -#include "asan_shadow_setup.hpp" -#include "ur_sanitizer_layer.hpp" - -namespace ur_sanitizer_layer { - -namespace cpu { - -constexpr size_t SHADOW_SIZE = 0x80000000000ULL; -uptr SHADOW_BEGIN; -uptr SHADOW_END; - -bool IsShadowMemInited = false; - -ur_result_t SetupShadowMemory(uptr &ShadowBegin, uptr &ShadowEnd) { - static ur_result_t Result = []() { - SHADOW_BEGIN = MmapNoReserve(0, SHADOW_SIZE); - if (SHADOW_BEGIN == 0) { - return UR_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - DontCoredumpRange(SHADOW_BEGIN, SHADOW_SIZE); - SHADOW_END = SHADOW_BEGIN + SHADOW_SIZE; - IsShadowMemInited = true; - return UR_RESULT_SUCCESS; - }(); - ShadowBegin = SHADOW_BEGIN; - ShadowEnd = SHADOW_END; - return Result; -} - -ur_result_t DestroyShadowMemory() { - if (!IsShadowMemInited) { - return UR_RESULT_SUCCESS; - } - if (!Munmap(SHADOW_BEGIN, SHADOW_SIZE)) { - return UR_RESULT_ERROR_UNKNOWN; - } - return UR_RESULT_SUCCESS; -} - -} // namespace cpu - -namespace pvc { -/// -/// USM Allocation Range (56 bits) -/// Host USM : 0x0000_0000_0000_0000 ~ 0x00ff_ffff_ffff_ffff -/// Shared USM : 0x0000_0000_0000_0000 ~ 0x0000_7fff_ffff_ffff -/// Device USM : 0xff00_0000_0000_0000 ~ 0xff00_ffff_ffff_ffff -/// -/// USM Allocation Range (AllocateHostAllocationsInHeapExtendedHost=0) -/// Host USM : 0x0000_0000_0000_0000 ~ 0x0000_7fff_ffff_ffff -/// Shared USM : 0x0000_0000_0000_0000 ~ 0x0000_7fff_ffff_ffff -/// Device USM : 0xff00_0000_0000_0000 ~ 0xff00_ffff_ffff_ffff -/// -/// Shadow Memory Mapping (SHADOW_SCALE=4, AllocateHostAllocationsInHeapExtendedHost=0) -/// Host/Shared USM : 0x0 ~ 0x07ff_ffff_ffff -/// Device USM : 0x0800_0000_0000 ~ 0x17ff_ffff_ffff -/// -constexpr size_t SHADOW_SIZE = 0x180000000000ULL; - -uptr LOW_SHADOW_BEGIN; -uptr HIGH_SHADOW_END; - -ur_context_handle_t ShadowContext; - -ur_result_t SetupShadowMemory(ur_context_handle_t Context, uptr &ShadowBegin, - uptr &ShadowEnd) { - // Currently, Level-Zero doesn't create independent VAs for each contexts, if we reserve - // shadow memory for each contexts, this will cause out-of-resource error when user uses - // multiple contexts. Therefore, we just create one shadow memory here. - static ur_result_t Result = [&Context]() { - // TODO: Protect Bad Zone - auto Result = getContext()->urDdiTable.VirtualMem.pfnReserve( - Context, nullptr, SHADOW_SIZE, (void **)&LOW_SHADOW_BEGIN); - if (Result == UR_RESULT_SUCCESS) { - HIGH_SHADOW_END = LOW_SHADOW_BEGIN + SHADOW_SIZE; - // Retain the context which reserves shadow memory - ShadowContext = Context; - getContext()->urDdiTable.Context.pfnRetain(Context); - } - return Result; - }(); - ShadowBegin = LOW_SHADOW_BEGIN; - ShadowEnd = HIGH_SHADOW_END; - return Result; -} - -ur_result_t DestroyShadowMemory() { - static ur_result_t Result = []() { - if (!ShadowContext) { - return UR_RESULT_SUCCESS; - } - auto Result = getContext()->urDdiTable.VirtualMem.pfnFree( - ShadowContext, (const void *)LOW_SHADOW_BEGIN, SHADOW_SIZE); - getContext()->urDdiTable.Context.pfnRelease(ShadowContext); - return Result; - }(); - return Result; -} - -} // namespace pvc - -namespace dg2 { -/// -/// USM Allocation Range (48 bits) -/// Host/Shared USM : 0x0000_0000_0000_0000 ~ 0x0000_7fff_ffff_ffff -/// Device USM : 0xffff_8000_0000_0000 ~ 0xffff_ffff_ffff_ffff -/// -/// Shadow Memory Mapping (SHADOW_SCALE=4) -/// Host/Shared USM : 0x0 ~ 0x07ff_ffff_ffff -/// Device USM : 0x0800_0000_0000 ~ 0x0fff_ffff_ffff -/// -constexpr size_t SHADOW_SIZE = 0x100000000000ULL; - -uptr LOW_SHADOW_BEGIN; -uptr HIGH_SHADOW_END; - -ur_context_handle_t ShadowContext; - -ur_result_t SetupShadowMemory(ur_context_handle_t Context, uptr &ShadowBegin, - uptr &ShadowEnd) { - // Currently, Level-Zero doesn't create independent VAs for each contexts, if we reserve - // shadow memory for each contexts, this will cause out-of-resource error when user uses - // multiple contexts. Therefore, we just create one shadow memory here. - static ur_result_t Result = [&Context]() { - // TODO: Protect Bad Zone - auto Result = getContext()->urDdiTable.VirtualMem.pfnReserve( - Context, nullptr, SHADOW_SIZE, (void **)&LOW_SHADOW_BEGIN); - if (Result == UR_RESULT_SUCCESS) { - HIGH_SHADOW_END = LOW_SHADOW_BEGIN + SHADOW_SIZE; - // Retain the context which reserves shadow memory - ShadowContext = Context; - getContext()->urDdiTable.Context.pfnRetain(Context); - } - return Result; - }(); - ShadowBegin = LOW_SHADOW_BEGIN; - ShadowEnd = HIGH_SHADOW_END; - return Result; -} - -ur_result_t DestroyShadowMemory() { - static ur_result_t Result = []() { - if (!ShadowContext) { - return UR_RESULT_SUCCESS; - } - auto Result = getContext()->urDdiTable.VirtualMem.pfnFree( - ShadowContext, (const void *)LOW_SHADOW_BEGIN, SHADOW_SIZE); - getContext()->urDdiTable.Context.pfnRelease(ShadowContext); - return Result; - }(); - return Result; -} - -} // namespace dg2 - -ur_result_t SetupShadowMemoryOnCPU(uptr &ShadowBegin, uptr &ShadowEnd) { - return cpu::SetupShadowMemory(ShadowBegin, ShadowEnd); -} - -ur_result_t DestroyShadowMemoryOnCPU() { return cpu::DestroyShadowMemory(); } - -ur_result_t SetupShadowMemoryOnPVC(ur_context_handle_t Context, - uptr &ShadowBegin, uptr &ShadowEnd) { - return pvc::SetupShadowMemory(Context, ShadowBegin, ShadowEnd); -} - -ur_result_t DestroyShadowMemoryOnPVC() { return pvc::DestroyShadowMemory(); } - -ur_result_t SetupShadowMemoryOnDG2(ur_context_handle_t Context, - uptr &ShadowBegin, uptr &ShadowEnd) { - return dg2::SetupShadowMemory(Context, ShadowBegin, ShadowEnd); -} - -ur_result_t DestroyShadowMemoryOnDG2() { return dg2::DestroyShadowMemory(); } - -} // namespace ur_sanitizer_layer diff --git a/source/loader/layers/sanitizer/asan_shadow_setup.hpp b/source/loader/layers/sanitizer/asan_shadow_setup.hpp deleted file mode 100644 index cc8a27fee2..0000000000 --- a/source/loader/layers/sanitizer/asan_shadow_setup.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * 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 asan_shadow_setup.hpp - * - */ - -#pragma once - -#include "common.hpp" - -namespace ur_sanitizer_layer { - -ur_result_t SetupShadowMemoryOnCPU(uptr &ShadowBegin, uptr &ShadowEnd); -ur_result_t DestroyShadowMemoryOnCPU(); - -ur_result_t SetupShadowMemoryOnPVC(ur_context_handle_t Context, - uptr &ShadowBegin, uptr &ShadowEnd); -ur_result_t DestroyShadowMemoryOnPVC(); - -ur_result_t SetupShadowMemoryOnDG2(ur_context_handle_t Context, - uptr &ShadowBegin, uptr &ShadowEnd); -ur_result_t DestroyShadowMemoryOnDG2(); - -} // namespace ur_sanitizer_layer diff --git a/source/loader/layers/sanitizer/ur_sanddi.cpp b/source/loader/layers/sanitizer/ur_sanddi.cpp index 8930049ea0..8ebeca5f7d 100644 --- a/source/loader/layers/sanitizer/ur_sanddi.cpp +++ b/source/loader/layers/sanitizer/ur_sanddi.cpp @@ -41,7 +41,7 @@ ur_result_t setupContext(ur_context_handle_t Context, uint32_t numDevices, DI->IsSupportSharedSystemUSM); getContext()->logger.info("Add {} into context {}", (void *)DI->Handle, (void *)Context); - if (!DI->ShadowOffset) { + if (!DI->Shadow) { UR_CALL(DI->allocShadowMemory(Context)); } CI->DeviceList.emplace_back(hDevice); @@ -175,6 +175,103 @@ __urdlllocal ur_result_t UR_APICALL urUSMFree( return getContext()->interceptor->releaseMemory(hContext, pMem); } +/////////////////////////////////////////////////////////////////////////////// +/// @brief Intercept function for urProgramCreateWithIL +__urdlllocal ur_result_t UR_APICALL urProgramCreateWithIL( + ur_context_handle_t hContext, ///< [in] handle of the context instance + const void *pIL, ///< [in] pointer to IL binary. + size_t length, ///< [in] length of `pIL` in bytes. + const ur_program_properties_t *pProperties, ///< [in][optional] pointer to program creation properties. + ur_program_handle_t *phProgram ///< [out] pointer to handle of program object created. +) { + auto pfnProgramCreateWithIL = + getContext()->urDdiTable.Program.pfnCreateWithIL; + + if (nullptr == pfnProgramCreateWithIL) { + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + + getContext()->logger.debug("==== urProgramCreateWithIL"); + + UR_CALL( + pfnProgramCreateWithIL(hContext, pIL, length, pProperties, phProgram)); + UR_CALL(getContext()->interceptor->insertProgram(*phProgram)); + + return UR_RESULT_SUCCESS; +} + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Intercept function for urProgramCreateWithBinary +__urdlllocal ur_result_t UR_APICALL urProgramCreateWithBinary( + ur_context_handle_t hContext, ///< [in] handle of the context instance + ur_device_handle_t hDevice, ///< [in] handle to device associated with binary. + size_t size, ///< [in] size in bytes. + const uint8_t *pBinary, ///< [in] pointer to binary. + const ur_program_properties_t *pProperties, ///< [in][optional] pointer to program creation properties. + ur_program_handle_t *phProgram ///< [out] pointer to handle of Program object created. +) { + auto pfnProgramCreateWithBinary = + getContext()->urDdiTable.Program.pfnCreateWithBinary; + + if (nullptr == pfnProgramCreateWithBinary) { + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + + getContext()->logger.debug("==== urProgramCreateWithBinary"); + + UR_CALL(pfnProgramCreateWithBinary(hContext, hDevice, size, pBinary, + pProperties, phProgram)); + UR_CALL(getContext()->interceptor->insertProgram(*phProgram)); + + return UR_RESULT_SUCCESS; +} + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Intercept function for urProgramCreateWithNativeHandle +__urdlllocal ur_result_t UR_APICALL urProgramCreateWithNativeHandle( + ur_native_handle_t hNativeProgram, ///< [in][nocheck] the native handle of the program. + ur_context_handle_t hContext, ///< [in] handle of the context instance + const ur_program_native_properties_t *pProperties, ///< [in][optional] pointer to native program properties struct. + ur_program_handle_t *phProgram ///< [out] pointer to the handle of the program object created. +) { + auto pfnProgramCreateWithNativeHandle = + getContext()->urDdiTable.Program.pfnCreateWithNativeHandle; + + if (nullptr == pfnProgramCreateWithNativeHandle) { + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + + getContext()->logger.debug("==== urProgramCreateWithNativeHandle"); + + UR_CALL(pfnProgramCreateWithNativeHandle(hNativeProgram, hContext, + pProperties, phProgram)); + UR_CALL(getContext()->interceptor->insertProgram(*phProgram)); + + return UR_RESULT_SUCCESS; +} + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Intercept function for urProgramRetain +__urdlllocal ur_result_t UR_APICALL urProgramRetain( + ur_program_handle_t hProgram ///< [in][retain] handle for the Program to retain +) { + auto pfnRetain = getContext()->urDdiTable.Program.pfnRetain; + + if (nullptr == pfnRetain) { + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + + getContext()->logger.debug("==== urProgramRetain"); + + UR_CALL(pfnRetain(hProgram)); + + auto ProgramInfo = getContext()->interceptor->getProgramInfo(hProgram); + UR_ASSERT(ProgramInfo != nullptr, UR_RESULT_ERROR_INVALID_VALUE); + ProgramInfo->RefCount++; + + return UR_RESULT_SUCCESS; +} + /////////////////////////////////////////////////////////////////////////////// /// @brief Intercept function for urProgramBuild __urdlllocal ur_result_t UR_APICALL urProgramBuild( @@ -283,6 +380,32 @@ ur_result_t UR_APICALL urProgramLinkExp( return UR_RESULT_SUCCESS; } +/////////////////////////////////////////////////////////////////////////////// +/// @brief Intercept function for urProgramRelease +ur_result_t UR_APICALL urProgramRelease( + ur_program_handle_t + hProgram ///< [in][release] handle for the Program to release +) { + auto pfnProgramRelease = getContext()->urDdiTable.Program.pfnRelease; + + if (nullptr == pfnProgramRelease) { + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + + getContext()->logger.debug("==== urProgramRelease"); + + UR_CALL(pfnProgramRelease(hProgram)); + + auto ProgramInfo = getContext()->interceptor->getProgramInfo(hProgram); + UR_ASSERT(ProgramInfo != nullptr, UR_RESULT_ERROR_INVALID_VALUE); + if (--ProgramInfo->RefCount == 0) { + UR_CALL(getContext()->interceptor->unregisterDeviceGlobals(hProgram)); + UR_CALL(getContext()->interceptor->eraseProgram(hProgram)); + } + + return UR_RESULT_SUCCESS; +} + /////////////////////////////////////////////////////////////////////////////// /// @brief Intercept function for urEnqueueKernelLaunch __urdlllocal ur_result_t UR_APICALL urEnqueueKernelLaunch( @@ -1485,8 +1608,15 @@ __urdlllocal ur_result_t UR_APICALL urGetProgramProcAddrTable( return UR_RESULT_ERROR_UNSUPPORTED_VERSION; } + pDdiTable->pfnCreateWithIL = ur_sanitizer_layer::urProgramCreateWithIL; + pDdiTable->pfnCreateWithBinary = + ur_sanitizer_layer::urProgramCreateWithBinary; + pDdiTable->pfnCreateWithNativeHandle = + ur_sanitizer_layer::urProgramCreateWithNativeHandle; pDdiTable->pfnBuild = ur_sanitizer_layer::urProgramBuild; pDdiTable->pfnLink = ur_sanitizer_layer::urProgramLink; + pDdiTable->pfnRetain = ur_sanitizer_layer::urProgramRetain; + pDdiTable->pfnRelease = ur_sanitizer_layer::urProgramRelease; return UR_RESULT_SUCCESS; } diff --git a/source/loader/layers/sanitizer/ur_sanitizer_utils.cpp b/source/loader/layers/sanitizer/ur_sanitizer_utils.cpp index feaff8757a..d81ec49a54 100644 --- a/source/loader/layers/sanitizer/ur_sanitizer_utils.cpp +++ b/source/loader/layers/sanitizer/ur_sanitizer_utils.cpp @@ -135,7 +135,7 @@ DeviceType GetDeviceType(ur_context_handle_t Context, assert(Result == UR_RESULT_SUCCESS && "getDeviceType() failed at allocating device USM"); // FIXME: There's no API querying the address bits of device, so we guess it by the - // value of device USM pointer (see "USM Allocation Range" in asan_shadow_setup.cpp) + // value of device USM pointer (see "USM Allocation Range" in asan_shadow.cpp) auto Type = DeviceType::UNKNOWN; if (Ptr >> 48 == 0xff00U) { Type = DeviceType::GPU_PVC; @@ -224,4 +224,15 @@ size_t GetVirtualMemGranularity(ur_context_handle_t Context, return Size; } +ur_result_t EnqueueUSMBlockingSet(ur_queue_handle_t Queue, void *Ptr, + char Value, size_t Size, uint32_t NumEvents, + const ur_event_handle_t *EventWaitList, + ur_event_handle_t *OutEvent) { + if (Size == 0) { + return UR_RESULT_SUCCESS; + } + return getContext()->urDdiTable.Enqueue.pfnUSMFill( + Queue, Ptr, 1, &Value, Size, NumEvents, EventWaitList, OutEvent); +} + } // namespace ur_sanitizer_layer diff --git a/source/loader/layers/sanitizer/ur_sanitizer_utils.hpp b/source/loader/layers/sanitizer/ur_sanitizer_utils.hpp index 44ddf46922..99ad2fc50f 100644 --- a/source/loader/layers/sanitizer/ur_sanitizer_utils.hpp +++ b/source/loader/layers/sanitizer/ur_sanitizer_utils.hpp @@ -53,4 +53,10 @@ size_t GetKernelPrivateMemorySize(ur_kernel_handle_t Kernel, size_t GetVirtualMemGranularity(ur_context_handle_t Context, ur_device_handle_t Device); +ur_result_t +EnqueueUSMBlockingSet(ur_queue_handle_t Queue, void *Ptr, char Value, + size_t Size, uint32_t NumEvents = 0, + const ur_event_handle_t *EventWaitList = nullptr, + ur_event_handle_t *OutEvent = nullptr); + } // namespace ur_sanitizer_layer From 9a435b28d3efdca477832c962f1a3ea0221b7c71 Mon Sep 17 00:00:00 2001 From: "Zhao, Maosu" Date: Tue, 24 Sep 2024 20:40:57 -0700 Subject: [PATCH 02/10] Add virtual destructor --- source/loader/layers/sanitizer/asan_shadow.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/loader/layers/sanitizer/asan_shadow.hpp b/source/loader/layers/sanitizer/asan_shadow.hpp index 5cd4878f0f..9b2d364c38 100644 --- a/source/loader/layers/sanitizer/asan_shadow.hpp +++ b/source/loader/layers/sanitizer/asan_shadow.hpp @@ -21,6 +21,8 @@ namespace ur_sanitizer_layer { struct ShadowMemory { ShadowMemory(ur_context_handle_t Context, ur_device_handle_t Device) : Context(Context), Device(Device) {} + + virtual ~ShadowMemory() {} virtual ur_result_t Setup() = 0; From a7fe6349c541f2509302af8ca227df47d4695946 Mon Sep 17 00:00:00 2001 From: Maosu Zhao Date: Wed, 25 Sep 2024 15:47:36 +0800 Subject: [PATCH 03/10] formatting --- .../loader/layers/sanitizer/asan_shadow.hpp | 16 +++----- source/loader/layers/sanitizer/ur_sanddi.cpp | 41 +++++++++++-------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/source/loader/layers/sanitizer/asan_shadow.hpp b/source/loader/layers/sanitizer/asan_shadow.hpp index 9b2d364c38..edca676141 100644 --- a/source/loader/layers/sanitizer/asan_shadow.hpp +++ b/source/loader/layers/sanitizer/asan_shadow.hpp @@ -12,8 +12,8 @@ #pragma once -#include "common.hpp" #include "asan_allocator.hpp" +#include "common.hpp" #include namespace ur_sanitizer_layer { @@ -21,7 +21,7 @@ namespace ur_sanitizer_layer { struct ShadowMemory { ShadowMemory(ur_context_handle_t Context, ur_device_handle_t Device) : Context(Context), Device(Device) {} - + virtual ~ShadowMemory() {} virtual ur_result_t Setup() = 0; @@ -63,9 +63,7 @@ struct ShadowMemoryCPU final : public ShadowMemory { virtual ur_result_t EnqueuePoisonShadow(ur_queue_handle_t Queue, uptr Ptr, uptr Size, u8 Value) override; - virtual size_t GetShadowSize() override { - return 0x80000000000ULL; - } + virtual size_t GetShadowSize() override { return 0x80000000000ULL; } }; struct ShadowMemoryGPU : public ShadowMemory { @@ -111,9 +109,7 @@ struct ShadowMemoryPVC final : public ShadowMemoryGPU { virtual uptr MemToShadow(uptr Ptr) override; - virtual size_t GetShadowSize() override { - return 0x180000000000ULL; - } + virtual size_t GetShadowSize() override { return 0x180000000000ULL; } }; /// Shadow Memory layout of GPU PVC device @@ -132,9 +128,7 @@ struct ShadowMemoryDG2 final : public ShadowMemoryGPU { virtual uptr MemToShadow(uptr Ptr) override; - virtual size_t GetShadowSize() override { - return 0x100000000000ULL; - } + virtual size_t GetShadowSize() override { return 0x100000000000ULL; } }; } // namespace ur_sanitizer_layer diff --git a/source/loader/layers/sanitizer/ur_sanddi.cpp b/source/loader/layers/sanitizer/ur_sanddi.cpp index 8ebeca5f7d..fec3046516 100644 --- a/source/loader/layers/sanitizer/ur_sanddi.cpp +++ b/source/loader/layers/sanitizer/ur_sanddi.cpp @@ -178,11 +178,13 @@ __urdlllocal ur_result_t UR_APICALL urUSMFree( /////////////////////////////////////////////////////////////////////////////// /// @brief Intercept function for urProgramCreateWithIL __urdlllocal ur_result_t UR_APICALL urProgramCreateWithIL( - ur_context_handle_t hContext, ///< [in] handle of the context instance - const void *pIL, ///< [in] pointer to IL binary. - size_t length, ///< [in] length of `pIL` in bytes. - const ur_program_properties_t *pProperties, ///< [in][optional] pointer to program creation properties. - ur_program_handle_t *phProgram ///< [out] pointer to handle of program object created. + ur_context_handle_t hContext, ///< [in] handle of the context instance + const void *pIL, ///< [in] pointer to IL binary. + size_t length, ///< [in] length of `pIL` in bytes. + const ur_program_properties_t * + pProperties, ///< [in][optional] pointer to program creation properties. + ur_program_handle_t + *phProgram ///< [out] pointer to handle of program object created. ) { auto pfnProgramCreateWithIL = getContext()->urDdiTable.Program.pfnCreateWithIL; @@ -203,12 +205,15 @@ __urdlllocal ur_result_t UR_APICALL urProgramCreateWithIL( /////////////////////////////////////////////////////////////////////////////// /// @brief Intercept function for urProgramCreateWithBinary __urdlllocal ur_result_t UR_APICALL urProgramCreateWithBinary( - ur_context_handle_t hContext, ///< [in] handle of the context instance - ur_device_handle_t hDevice, ///< [in] handle to device associated with binary. - size_t size, ///< [in] size in bytes. - const uint8_t *pBinary, ///< [in] pointer to binary. - const ur_program_properties_t *pProperties, ///< [in][optional] pointer to program creation properties. - ur_program_handle_t *phProgram ///< [out] pointer to handle of Program object created. + ur_context_handle_t hContext, ///< [in] handle of the context instance + ur_device_handle_t + hDevice, ///< [in] handle to device associated with binary. + size_t size, ///< [in] size in bytes. + const uint8_t *pBinary, ///< [in] pointer to binary. + const ur_program_properties_t * + pProperties, ///< [in][optional] pointer to program creation properties. + ur_program_handle_t + *phProgram ///< [out] pointer to handle of Program object created. ) { auto pfnProgramCreateWithBinary = getContext()->urDdiTable.Program.pfnCreateWithBinary; @@ -229,10 +234,13 @@ __urdlllocal ur_result_t UR_APICALL urProgramCreateWithBinary( /////////////////////////////////////////////////////////////////////////////// /// @brief Intercept function for urProgramCreateWithNativeHandle __urdlllocal ur_result_t UR_APICALL urProgramCreateWithNativeHandle( - ur_native_handle_t hNativeProgram, ///< [in][nocheck] the native handle of the program. - ur_context_handle_t hContext, ///< [in] handle of the context instance - const ur_program_native_properties_t *pProperties, ///< [in][optional] pointer to native program properties struct. - ur_program_handle_t *phProgram ///< [out] pointer to the handle of the program object created. + ur_native_handle_t + hNativeProgram, ///< [in][nocheck] the native handle of the program. + ur_context_handle_t hContext, ///< [in] handle of the context instance + const ur_program_native_properties_t * + pProperties, ///< [in][optional] pointer to native program properties struct. + ur_program_handle_t * + phProgram ///< [out] pointer to the handle of the program object created. ) { auto pfnProgramCreateWithNativeHandle = getContext()->urDdiTable.Program.pfnCreateWithNativeHandle; @@ -253,7 +261,8 @@ __urdlllocal ur_result_t UR_APICALL urProgramCreateWithNativeHandle( /////////////////////////////////////////////////////////////////////////////// /// @brief Intercept function for urProgramRetain __urdlllocal ur_result_t UR_APICALL urProgramRetain( - ur_program_handle_t hProgram ///< [in][retain] handle for the Program to retain + ur_program_handle_t + hProgram ///< [in][retain] handle for the Program to retain ) { auto pfnRetain = getContext()->urDdiTable.Program.pfnRetain; From 0a5221a2a78b130cd08c62e67b4aed79493b308c Mon Sep 17 00:00:00 2001 From: Maosu Zhao Date: Wed, 25 Sep 2024 16:59:36 +0800 Subject: [PATCH 04/10] Remove unnecessary virtual keyword --- .../loader/layers/sanitizer/asan_shadow.hpp | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/source/loader/layers/sanitizer/asan_shadow.hpp b/source/loader/layers/sanitizer/asan_shadow.hpp index edca676141..ccc77b5a97 100644 --- a/source/loader/layers/sanitizer/asan_shadow.hpp +++ b/source/loader/layers/sanitizer/asan_shadow.hpp @@ -54,30 +54,29 @@ struct ShadowMemoryCPU final : public ShadowMemory { ShadowMemoryCPU(ur_context_handle_t Context, ur_device_handle_t Device) : ShadowMemory(Context, Device) {} - virtual ur_result_t Setup() override; + ur_result_t Setup() override; - virtual ur_result_t Destory() override; + ur_result_t Destory() override; - virtual uptr MemToShadow(uptr Ptr) override; + uptr MemToShadow(uptr Ptr) override; - virtual ur_result_t EnqueuePoisonShadow(ur_queue_handle_t Queue, uptr Ptr, - uptr Size, u8 Value) override; + ur_result_t EnqueuePoisonShadow(ur_queue_handle_t Queue, uptr Ptr, + uptr Size, u8 Value) override; - virtual size_t GetShadowSize() override { return 0x80000000000ULL; } + size_t GetShadowSize() override { return 0x80000000000ULL; } }; struct ShadowMemoryGPU : public ShadowMemory { ShadowMemoryGPU(ur_context_handle_t Context, ur_device_handle_t Device) : ShadowMemory(Context, Device) {} - virtual ur_result_t Setup() override; + ur_result_t Setup() override; - virtual ur_result_t Destory() override; - virtual ur_result_t EnqueuePoisonShadow(ur_queue_handle_t Queue, uptr Ptr, - uptr Size, u8 Value) override final; + ur_result_t Destory() override; + ur_result_t EnqueuePoisonShadow(ur_queue_handle_t Queue, uptr Ptr, + uptr Size, u8 Value) override final; - virtual ur_result_t - ReleaseShadow(std::shared_ptr AI) override final; + ur_result_t ReleaseShadow(std::shared_ptr AI) override final; ur_mutex VirtualMemMapsMutex; @@ -107,9 +106,9 @@ struct ShadowMemoryPVC final : public ShadowMemoryGPU { ShadowMemoryPVC(ur_context_handle_t Context, ur_device_handle_t Device) : ShadowMemoryGPU(Context, Device) {} - virtual uptr MemToShadow(uptr Ptr) override; + uptr MemToShadow(uptr Ptr) override; - virtual size_t GetShadowSize() override { return 0x180000000000ULL; } + size_t GetShadowSize() override { return 0x180000000000ULL; } }; /// Shadow Memory layout of GPU PVC device @@ -126,9 +125,9 @@ struct ShadowMemoryDG2 final : public ShadowMemoryGPU { ShadowMemoryDG2(ur_context_handle_t Context, ur_device_handle_t Device) : ShadowMemoryGPU(Context, Device) {} - virtual uptr MemToShadow(uptr Ptr) override; + uptr MemToShadow(uptr Ptr) override; - virtual size_t GetShadowSize() override { return 0x100000000000ULL; } + size_t GetShadowSize() override { return 0x100000000000ULL; } }; } // namespace ur_sanitizer_layer From 9592d2ee2d0bdb90272e028174d66721989a53f1 Mon Sep 17 00:00:00 2001 From: Maosu Zhao Date: Thu, 26 Sep 2024 11:49:36 +0800 Subject: [PATCH 05/10] Fix init problem on platform with multi GPU devices --- .../layers/sanitizer/asan_interceptor.cpp | 11 ---- .../loader/layers/sanitizer/asan_shadow.cpp | 58 ++++++++++++++----- .../loader/layers/sanitizer/asan_shadow.hpp | 2 - 3 files changed, 45 insertions(+), 26 deletions(-) diff --git a/source/loader/layers/sanitizer/asan_interceptor.cpp b/source/loader/layers/sanitizer/asan_interceptor.cpp index f8c7272e27..0d2e1ffaeb 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.cpp +++ b/source/loader/layers/sanitizer/asan_interceptor.cpp @@ -307,17 +307,6 @@ ur_result_t DeviceInfo::allocShadowMemory(ur_context_handle_t Context) { getContext()->logger.info("ShadowMemory(Global): {} - {}", (void *)Shadow->ShadowBegin, (void *)Shadow->ShadowEnd); - - // Set shadow memory for null pointer - ManagedQueue Queue(Context, Handle); - - auto URes = - Shadow->EnqueuePoisonShadow(Queue, 0, 1, kNullPointerRedzoneMagic); - if (URes != UR_RESULT_SUCCESS) { - getContext()->logger.error("enqueueMemSetShadow(NullPointerRZ): {}", - URes); - return URes; - } return UR_RESULT_SUCCESS; } diff --git a/source/loader/layers/sanitizer/asan_shadow.cpp b/source/loader/layers/sanitizer/asan_shadow.cpp index 1a4d7f546c..7c6ffea9f2 100644 --- a/source/loader/layers/sanitizer/asan_shadow.cpp +++ b/source/loader/layers/sanitizer/asan_shadow.cpp @@ -19,22 +19,36 @@ namespace ur_sanitizer_layer { ur_result_t ShadowMemoryCPU::Setup() { + static uptr Begin = 0, End = 0; static ur_result_t Result = [this]() { size_t ShadowSize = GetShadowSize(); - ShadowBegin = MmapNoReserve(0, ShadowSize); - if (ShadowBegin == 0) { + Begin = MmapNoReserve(0, ShadowSize); + if (Begin == 0) { return UR_RESULT_ERROR_OUT_OF_HOST_MEMORY; } - DontCoredumpRange(ShadowBegin, ShadowSize); - ShadowEnd = ShadowBegin + ShadowSize; - IsShadowMemInited = true; - return UR_RESULT_SUCCESS; + DontCoredumpRange(Begin, ShadowSize); + End = Begin + ShadowSize; + + ShadowBegin = Begin; + ShadowEnd = End; + + // Set shadow memory for null pointer + auto URes = EnqueuePoisonShadow({}, 0, 1, kNullPointerRedzoneMagic); + if (URes != UR_RESULT_SUCCESS) { + getContext()->logger.error("EnqueuePoisonShadow(NullPointerRZ): {}", + URes); + return URes; + } + return URes; }(); + assert(Begin != 0 && End != 0); + ShadowBegin = Begin; + ShadowEnd = End; return Result; } ur_result_t ShadowMemoryCPU::Destory() { - if (!IsShadowMemInited) { + if (ShadowBegin == 0) { return UR_RESULT_SUCCESS; } static ur_result_t Result = [this]() { @@ -68,6 +82,7 @@ ur_result_t ShadowMemoryCPU::EnqueuePoisonShadow(ur_queue_handle_t, uptr Ptr, } ur_result_t ShadowMemoryGPU::Setup() { + static uptr Begin = 0, End = 0; // Currently, Level-Zero doesn't create independent VAs for each contexts, if we reserve // shadow memory for each contexts, this will cause out-of-resource error when user uses // multiple contexts. Therefore, we just create one shadow memory here. @@ -75,20 +90,36 @@ ur_result_t ShadowMemoryGPU::Setup() { size_t ShadowSize = GetShadowSize(); // TODO: Protect Bad Zone auto Result = getContext()->urDdiTable.VirtualMem.pfnReserve( - Context, nullptr, ShadowSize, (void **)&ShadowBegin); + Context, nullptr, ShadowSize, (void **)&Begin); if (Result == UR_RESULT_SUCCESS) { - ShadowEnd = ShadowBegin + ShadowSize; + End = Begin + ShadowSize; // Retain the context which reserves shadow memory getContext()->urDdiTable.Context.pfnRetain(Context); } - IsShadowMemInited = true; + + ShadowBegin = Begin; + ShadowEnd = End; + + // Set shadow memory for null pointer + ManagedQueue Queue(Context, Device); + + auto URes = EnqueuePoisonShadow({}, 0, 1, kNullPointerRedzoneMagic); + if (URes != UR_RESULT_SUCCESS) { + getContext()->logger.error("EnqueuePoisonShadow(NullPointerRZ): {}", + URes); + return URes; + } + return URes; return Result; }(); + assert(Begin != 0 && End != 0); + ShadowBegin = Begin; + ShadowEnd = End; return Result; } ur_result_t ShadowMemoryGPU::Destory() { - if (!IsShadowMemInited) { + if (ShadowBegin == 0) { return UR_RESULT_SUCCESS; } static ur_result_t Result = [this]() { @@ -135,7 +166,7 @@ ur_result_t ShadowMemoryGPU::EnqueuePoisonShadow(ur_queue_handle_t Queue, Context, (void *)MappedPtr, PageSize, PhysicalMem, 0, UR_VIRTUAL_MEM_ACCESS_FLAG_READ_WRITE); if (URes != UR_RESULT_SUCCESS) { - getContext()->logger.debug("urVirtualMemMap({}, {}): {}", + getContext()->logger.error("urVirtualMemMap({}, {}): {}", (void *)MappedPtr, PageSize, URes); return URes; @@ -157,7 +188,8 @@ ur_result_t ShadowMemoryGPU::EnqueuePoisonShadow(ur_queue_handle_t Queue, VirtualMemMaps[MappedPtr].first = PhysicalMem; } - // We don't need to record virtual memory map for null pointer. + // We don't need to record virtual memory map for null pointer, + // since it doesn't have an alloc info. if (Ptr == 0) { continue; } diff --git a/source/loader/layers/sanitizer/asan_shadow.hpp b/source/loader/layers/sanitizer/asan_shadow.hpp index ccc77b5a97..1753239d63 100644 --- a/source/loader/layers/sanitizer/asan_shadow.hpp +++ b/source/loader/layers/sanitizer/asan_shadow.hpp @@ -46,8 +46,6 @@ struct ShadowMemory { uptr ShadowBegin = 0; uptr ShadowEnd = 0; - - bool IsShadowMemInited = false; }; struct ShadowMemoryCPU final : public ShadowMemory { From fbf564b39dde9844f4cc4835989e7a554e0c23ea Mon Sep 17 00:00:00 2001 From: "Zhao, Maosu" Date: Thu, 26 Sep 2024 07:26:45 +0200 Subject: [PATCH 06/10] Minor fix --- source/loader/layers/sanitizer/asan_shadow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/loader/layers/sanitizer/asan_shadow.cpp b/source/loader/layers/sanitizer/asan_shadow.cpp index 7c6ffea9f2..af2fe83192 100644 --- a/source/loader/layers/sanitizer/asan_shadow.cpp +++ b/source/loader/layers/sanitizer/asan_shadow.cpp @@ -103,7 +103,7 @@ ur_result_t ShadowMemoryGPU::Setup() { // Set shadow memory for null pointer ManagedQueue Queue(Context, Device); - auto URes = EnqueuePoisonShadow({}, 0, 1, kNullPointerRedzoneMagic); + auto URes = EnqueuePoisonShadow(Queue, 0, 1, kNullPointerRedzoneMagic); if (URes != UR_RESULT_SUCCESS) { getContext()->logger.error("EnqueuePoisonShadow(NullPointerRZ): {}", URes); From 87e7499c04070b08aff16450545c135d46424054 Mon Sep 17 00:00:00 2001 From: "Zhao, Maosu" Date: Fri, 27 Sep 2024 04:06:58 +0200 Subject: [PATCH 07/10] Change shadow memory object to singleton --- .../layers/sanitizer/asan_interceptor.cpp | 12 +--- .../layers/sanitizer/asan_interceptor.hpp | 2 +- .../loader/layers/sanitizer/asan_shadow.cpp | 56 ++++++++++--------- .../loader/layers/sanitizer/asan_shadow.hpp | 4 ++ 4 files changed, 38 insertions(+), 36 deletions(-) diff --git a/source/loader/layers/sanitizer/asan_interceptor.cpp b/source/loader/layers/sanitizer/asan_interceptor.cpp index 0d2e1ffaeb..dbae3678f4 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.cpp +++ b/source/loader/layers/sanitizer/asan_interceptor.cpp @@ -293,16 +293,8 @@ ur_result_t SanitizerInterceptor::postLaunchKernel(ur_kernel_handle_t Kernel, } ur_result_t DeviceInfo::allocShadowMemory(ur_context_handle_t Context) { - if (Type == DeviceType::CPU) { - Shadow = std::make_unique(Context, Handle); - } else if (Type == DeviceType::GPU_PVC) { - Shadow = std::make_unique(Context, Handle); - } else if (Type == DeviceType::GPU_DG2) { - Shadow = std::make_unique(Context, Handle); - } else { - getContext()->logger.error("Unsupport device type"); - return UR_RESULT_ERROR_INVALID_ARGUMENT; - } + Shadow = GetShadowMemory(Context, Handle, Type); + assert(Shadow && "Failed to get shadow memory"); UR_CALL(Shadow->Setup()); getContext()->logger.info("ShadowMemory(Global): {} - {}", (void *)Shadow->ShadowBegin, diff --git a/source/loader/layers/sanitizer/asan_interceptor.hpp b/source/loader/layers/sanitizer/asan_interceptor.hpp index 262d6ca20c..89730c748f 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.hpp +++ b/source/loader/layers/sanitizer/asan_interceptor.hpp @@ -40,7 +40,7 @@ struct DeviceInfo { DeviceType Type = DeviceType::UNKNOWN; size_t Alignment = 0; - std::unique_ptr Shadow; + std::shared_ptr Shadow; // Device features bool IsSupportSharedSystemUSM = false; diff --git a/source/loader/layers/sanitizer/asan_shadow.cpp b/source/loader/layers/sanitizer/asan_shadow.cpp index af2fe83192..1f3ae18986 100644 --- a/source/loader/layers/sanitizer/asan_shadow.cpp +++ b/source/loader/layers/sanitizer/asan_shadow.cpp @@ -18,19 +18,36 @@ namespace ur_sanitizer_layer { +std::shared_ptr GetShadowMemory(ur_context_handle_t Context, + ur_device_handle_t Device, + DeviceType Type) { + if (Type == DeviceType::CPU) { + static std::shared_ptr ShadowCPU = + std::make_shared(Context, Device); + return ShadowCPU; + } else if (Type == DeviceType::GPU_PVC) { + static std::shared_ptr ShadowPVC = + std::make_shared(Context, Device); + return ShadowPVC; + } else if (Type == DeviceType::GPU_DG2) { + static std::shared_ptr ShadowDG2 = + std::make_shared(Context, Device); + return ShadowDG2; + } else { + getContext()->logger.error("Unsupport device type"); + return nullptr; + } +} + ur_result_t ShadowMemoryCPU::Setup() { - static uptr Begin = 0, End = 0; static ur_result_t Result = [this]() { size_t ShadowSize = GetShadowSize(); - Begin = MmapNoReserve(0, ShadowSize); - if (Begin == 0) { + ShadowBegin = MmapNoReserve(0, ShadowSize); + if (ShadowBegin == 0) { return UR_RESULT_ERROR_OUT_OF_HOST_MEMORY; } - DontCoredumpRange(Begin, ShadowSize); - End = Begin + ShadowSize; - - ShadowBegin = Begin; - ShadowEnd = End; + DontCoredumpRange(ShadowBegin, ShadowSize); + ShadowEnd = ShadowBegin + ShadowSize; // Set shadow memory for null pointer auto URes = EnqueuePoisonShadow({}, 0, 1, kNullPointerRedzoneMagic); @@ -41,9 +58,6 @@ ur_result_t ShadowMemoryCPU::Setup() { } return URes; }(); - assert(Begin != 0 && End != 0); - ShadowBegin = Begin; - ShadowEnd = End; return Result; } @@ -82,7 +96,6 @@ ur_result_t ShadowMemoryCPU::EnqueuePoisonShadow(ur_queue_handle_t, uptr Ptr, } ur_result_t ShadowMemoryGPU::Setup() { - static uptr Begin = 0, End = 0; // Currently, Level-Zero doesn't create independent VAs for each contexts, if we reserve // shadow memory for each contexts, this will cause out-of-resource error when user uses // multiple contexts. Therefore, we just create one shadow memory here. @@ -90,31 +103,24 @@ ur_result_t ShadowMemoryGPU::Setup() { size_t ShadowSize = GetShadowSize(); // TODO: Protect Bad Zone auto Result = getContext()->urDdiTable.VirtualMem.pfnReserve( - Context, nullptr, ShadowSize, (void **)&Begin); + Context, nullptr, ShadowSize, (void **)&ShadowBegin); if (Result == UR_RESULT_SUCCESS) { - End = Begin + ShadowSize; + ShadowEnd = ShadowBegin + ShadowSize; // Retain the context which reserves shadow memory getContext()->urDdiTable.Context.pfnRetain(Context); } - ShadowBegin = Begin; - ShadowEnd = End; - // Set shadow memory for null pointer ManagedQueue Queue(Context, Device); - auto URes = EnqueuePoisonShadow(Queue, 0, 1, kNullPointerRedzoneMagic); - if (URes != UR_RESULT_SUCCESS) { + Result = EnqueuePoisonShadow(Queue, 0, 1, kNullPointerRedzoneMagic); + if (Result != UR_RESULT_SUCCESS) { getContext()->logger.error("EnqueuePoisonShadow(NullPointerRZ): {}", - URes); - return URes; + Result); + return Result; } - return URes; return Result; }(); - assert(Begin != 0 && End != 0); - ShadowBegin = Begin; - ShadowEnd = End; return Result; } diff --git a/source/loader/layers/sanitizer/asan_shadow.hpp b/source/loader/layers/sanitizer/asan_shadow.hpp index 1753239d63..7ae095062a 100644 --- a/source/loader/layers/sanitizer/asan_shadow.hpp +++ b/source/loader/layers/sanitizer/asan_shadow.hpp @@ -128,4 +128,8 @@ struct ShadowMemoryDG2 final : public ShadowMemoryGPU { size_t GetShadowSize() override { return 0x100000000000ULL; } }; +std::shared_ptr GetShadowMemory(ur_context_handle_t Context, + ur_device_handle_t Device, + DeviceType Type); + } // namespace ur_sanitizer_layer From 757663d74b114ef42a3bbf60300a1e32f1954222 Mon Sep 17 00:00:00 2001 From: Maosu Zhao Date: Sun, 29 Sep 2024 11:05:11 +0800 Subject: [PATCH 08/10] Do enqueue write sanitizer globals in registerProgram function --- .../layers/sanitizer/asan_interceptor.cpp | 80 +++++++++---------- .../layers/sanitizer/asan_interceptor.hpp | 6 +- source/loader/layers/sanitizer/ur_sanddi.cpp | 15 ++-- 3 files changed, 48 insertions(+), 53 deletions(-) diff --git a/source/loader/layers/sanitizer/asan_interceptor.cpp b/source/loader/layers/sanitizer/asan_interceptor.cpp index dbae3678f4..f61de9b7c3 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.cpp +++ b/source/loader/layers/sanitizer/asan_interceptor.cpp @@ -399,9 +399,8 @@ ur_result_t SanitizerInterceptor::updateShadowMemory( return UR_RESULT_SUCCESS; } -ur_result_t -SanitizerInterceptor::registerDeviceGlobals(ur_context_handle_t Context, - ur_program_handle_t Program) { +ur_result_t SanitizerInterceptor::registerProgram(ur_context_handle_t Context, + ur_program_handle_t Program) { std::vector Devices = GetProgramDevices(Program); auto ContextInfo = getContextInfo(Context); @@ -409,6 +408,42 @@ SanitizerInterceptor::registerDeviceGlobals(ur_context_handle_t Context, for (auto Device : Devices) { ManagedQueue Queue(Context, Device); + auto DeviceInfo = getDeviceInfo(Device); + + // Write global variable to program + auto EnqueueWriteGlobal = [&Queue, &Program]( + const char *Name, const void *Value, + size_t Size, bool ReportWarning = true) { + auto Result = + getContext()->urDdiTable.Enqueue.pfnDeviceGlobalVariableWrite( + Queue, Program, Name, false, Size, 0, Value, 0, nullptr, + nullptr); + if (ReportWarning && Result != UR_RESULT_SUCCESS) { + getContext()->logger.warning( + "Failed to write device global \"{}\": {}", Name, Result); + return false; + } + return true; + }; + + // Write debug + // We use "uint64_t" here because EnqueueWriteGlobal will fail when it's "uint32_t" + // Because EnqueueWriteGlobal is a async write, so + // we need to extend its lifetime + static uint64_t Debug = Options(logger).Debug ? 1 : 0; + EnqueueWriteGlobal(kSPIR_AsanDebug, &Debug, sizeof(Debug), false); + + // Write shadow memory offset for global memory + EnqueueWriteGlobal(kSPIR_AsanShadowMemoryGlobalStart, + &DeviceInfo->Shadow->ShadowBegin, + sizeof(DeviceInfo->Shadow->ShadowBegin)); + EnqueueWriteGlobal(kSPIR_AsanShadowMemoryGlobalEnd, + &DeviceInfo->Shadow->ShadowEnd, + sizeof(DeviceInfo->Shadow->ShadowEnd)); + + // Write device type + EnqueueWriteGlobal(kSPIR_DeviceType, &DeviceInfo->Type, + sizeof(DeviceInfo->Type)); uint64_t NumOfDeviceGlobal; auto Result = @@ -432,7 +467,6 @@ SanitizerInterceptor::registerDeviceGlobals(ur_context_handle_t Context, return Result; } - auto DeviceInfo = getDeviceInfo(Device); for (size_t i = 0; i < NumOfDeviceGlobal; i++) { auto AI = std::make_shared( AllocInfo{GVInfos[i].Addr, @@ -461,7 +495,7 @@ SanitizerInterceptor::registerDeviceGlobals(ur_context_handle_t Context, } ur_result_t -SanitizerInterceptor::unregisterDeviceGlobals(ur_program_handle_t Program) { +SanitizerInterceptor::unregisterProgram(ur_program_handle_t Program) { auto ProgramInfo = getProgramInfo(Program); std::scoped_lock Guard( @@ -597,7 +631,6 @@ ur_result_t SanitizerInterceptor::prepareLaunch( ur_context_handle_t Context, std::shared_ptr &DeviceInfo, ur_queue_handle_t Queue, ur_kernel_handle_t Kernel, USMLaunchInfo &LaunchInfo) { - auto Program = GetProgram(Kernel); do { auto KernelInfo = getKernelInfo(Kernel); @@ -648,41 +681,6 @@ ur_result_t SanitizerInterceptor::prepareLaunch( } } - // Write global variable to program - auto EnqueueWriteGlobal = [Queue, Program]( - const char *Name, const void *Value, - size_t Size, bool ReportWarning = true) { - auto Result = - getContext()->urDdiTable.Enqueue.pfnDeviceGlobalVariableWrite( - Queue, Program, Name, false, Size, 0, Value, 0, nullptr, - nullptr); - if (ReportWarning && Result != UR_RESULT_SUCCESS) { - getContext()->logger.warning( - "Failed to write device global \"{}\": {}", Name, Result); - return false; - } - return true; - }; - - // Write debug - // We use "uint64_t" here because EnqueueWriteGlobal will fail when it's "uint32_t" - // Because EnqueueWriteGlobal is a async write, so - // we need to extend its lifetime - static uint64_t Debug = Options(logger).Debug ? 1 : 0; - EnqueueWriteGlobal(kSPIR_AsanDebug, &Debug, sizeof(Debug), false); - - // Write shadow memory offset for global memory - EnqueueWriteGlobal(kSPIR_AsanShadowMemoryGlobalStart, - &DeviceInfo->Shadow->ShadowBegin, - sizeof(DeviceInfo->Shadow->ShadowBegin)); - EnqueueWriteGlobal(kSPIR_AsanShadowMemoryGlobalEnd, - &DeviceInfo->Shadow->ShadowEnd, - sizeof(DeviceInfo->Shadow->ShadowEnd)); - - // Write device type - EnqueueWriteGlobal(kSPIR_DeviceType, &DeviceInfo->Type, - sizeof(DeviceInfo->Type)); - if (LaunchInfo.LocalWorkSize.empty()) { LaunchInfo.LocalWorkSize.resize(LaunchInfo.WorkDim); auto URes = diff --git a/source/loader/layers/sanitizer/asan_interceptor.hpp b/source/loader/layers/sanitizer/asan_interceptor.hpp index 89730c748f..b4fa67a85a 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.hpp +++ b/source/loader/layers/sanitizer/asan_interceptor.hpp @@ -195,10 +195,10 @@ class SanitizerInterceptor { AllocType Type, void **ResultPtr); ur_result_t releaseMemory(ur_context_handle_t Context, void *Ptr); - ur_result_t registerDeviceGlobals(ur_context_handle_t Context, - ur_program_handle_t Program); + ur_result_t registerProgram(ur_context_handle_t Context, + ur_program_handle_t Program); - ur_result_t unregisterDeviceGlobals(ur_program_handle_t Program); + ur_result_t unregisterProgram(ur_program_handle_t Program); ur_result_t preLaunchKernel(ur_kernel_handle_t Kernel, ur_queue_handle_t Queue, diff --git a/source/loader/layers/sanitizer/ur_sanddi.cpp b/source/loader/layers/sanitizer/ur_sanddi.cpp index fec3046516..b2ed6adcf8 100644 --- a/source/loader/layers/sanitizer/ur_sanddi.cpp +++ b/source/loader/layers/sanitizer/ur_sanddi.cpp @@ -298,8 +298,7 @@ __urdlllocal ur_result_t UR_APICALL urProgramBuild( UR_CALL(pfnProgramBuild(hContext, hProgram, pOptions)); - UR_CALL( - getContext()->interceptor->registerDeviceGlobals(hContext, hProgram)); + UR_CALL(getContext()->interceptor->registerProgram(hContext, hProgram)); return UR_RESULT_SUCCESS; } @@ -323,8 +322,8 @@ __urdlllocal ur_result_t UR_APICALL urProgramBuildExp( getContext()->logger.debug("==== urProgramBuildExp"); UR_CALL(pfnBuildExp(hProgram, numDevices, phDevices, pOptions)); - UR_CALL(getContext()->interceptor->registerDeviceGlobals( - GetContext(hProgram), hProgram)); + UR_CALL(getContext()->interceptor->registerProgram(GetContext(hProgram), + hProgram)); return UR_RESULT_SUCCESS; } @@ -351,8 +350,7 @@ __urdlllocal ur_result_t UR_APICALL urProgramLink( UR_CALL(pfnProgramLink(hContext, count, phPrograms, pOptions, phProgram)); - UR_CALL( - getContext()->interceptor->registerDeviceGlobals(hContext, *phProgram)); + UR_CALL(getContext()->interceptor->registerProgram(hContext, *phProgram)); return UR_RESULT_SUCCESS; } @@ -383,8 +381,7 @@ ur_result_t UR_APICALL urProgramLinkExp( UR_CALL(pfnProgramLinkExp(hContext, numDevices, phDevices, count, phPrograms, pOptions, phProgram)); - UR_CALL( - getContext()->interceptor->registerDeviceGlobals(hContext, *phProgram)); + UR_CALL(getContext()->interceptor->registerProgram(hContext, *phProgram)); return UR_RESULT_SUCCESS; } @@ -408,7 +405,7 @@ ur_result_t UR_APICALL urProgramRelease( auto ProgramInfo = getContext()->interceptor->getProgramInfo(hProgram); UR_ASSERT(ProgramInfo != nullptr, UR_RESULT_ERROR_INVALID_VALUE); if (--ProgramInfo->RefCount == 0) { - UR_CALL(getContext()->interceptor->unregisterDeviceGlobals(hProgram)); + UR_CALL(getContext()->interceptor->unregisterProgram(hProgram)); UR_CALL(getContext()->interceptor->eraseProgram(hProgram)); } From 60743369476c08850e2b9e8479ff09634814821f Mon Sep 17 00:00:00 2001 From: Maosu Zhao Date: Mon, 30 Sep 2024 10:57:53 +0800 Subject: [PATCH 09/10] Enable quarantine by default and set the size to 8MB Don't release shadow memory if quarantine is disabled --- source/loader/layers/sanitizer/asan_interceptor.cpp | 9 --------- source/loader/layers/sanitizer/asan_options.hpp | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/source/loader/layers/sanitizer/asan_interceptor.cpp b/source/loader/layers/sanitizer/asan_interceptor.cpp index f61de9b7c3..a9f9c44dcb 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.cpp +++ b/source/loader/layers/sanitizer/asan_interceptor.cpp @@ -198,15 +198,6 @@ ur_result_t SanitizerInterceptor::releaseMemory(ur_context_handle_t Context, getContext()->logger.debug("Free: {}", (void *)AllocInfo->AllocBegin); std::scoped_lock Guard(m_AllocationMapMutex); m_AllocationMap.erase(AllocInfoIt); - if (AllocInfo->Type == AllocType::HOST_USM) { - for (auto &Device : ContextInfo->DeviceList) { - UR_CALL( - getDeviceInfo(Device)->Shadow->ReleaseShadow(AllocInfo)); - } - } else { - UR_CALL(getDeviceInfo(AllocInfo->Device) - ->Shadow->ReleaseShadow(AllocInfo)); - } return getContext()->urDdiTable.USM.pfnFree( Context, (void *)(AllocInfo->AllocBegin)); } diff --git a/source/loader/layers/sanitizer/asan_options.hpp b/source/loader/layers/sanitizer/asan_options.hpp index eb3f6bb03d..838fd52a6e 100644 --- a/source/loader/layers/sanitizer/asan_options.hpp +++ b/source/loader/layers/sanitizer/asan_options.hpp @@ -35,7 +35,7 @@ struct AsanOptions { bool Debug = false; uint64_t MinRZSize = 16; uint64_t MaxRZSize = 2048; - uint32_t MaxQuarantineSizeMB = 0; + uint32_t MaxQuarantineSizeMB = 8; bool DetectLocals = true; bool DetectPrivates = true; bool DetectKernelArguments = true; From 3ba2a7870941fd2630228eb907fe5ff0fa1d5de1 Mon Sep 17 00:00:00 2001 From: "Zhao, Maosu" Date: Wed, 9 Oct 2024 09:46:29 +0200 Subject: [PATCH 10/10] Minor update --- source/loader/layers/sanitizer/asan_interceptor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/loader/layers/sanitizer/asan_interceptor.cpp b/source/loader/layers/sanitizer/asan_interceptor.cpp index 29fc377c21..38bb4479f2 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.cpp +++ b/source/loader/layers/sanitizer/asan_interceptor.cpp @@ -31,12 +31,12 @@ SanitizerInterceptor::SanitizerInterceptor() { } SanitizerInterceptor::~SanitizerInterceptor() { + // We must release these objects before releasing adapters, since + // they may use the adapter in their destructor for (const auto &[_, DeviceInfo] : m_DeviceMap) { DeviceInfo->Shadow->Destory(); } - // We must release these objects before releasing adapters, since - // they may use the adapter in their destructor m_Quarantine = nullptr; m_MemBufferMap.clear(); m_AllocationMap.clear();