Skip to content

Commit 9b936b5

Browse files
authored
Merge pull request #1354 from AllanZyne/sanitizer-device-global
[DeviceSanitizer] Support detecting out-of-bounds error on DeviceGlobals
2 parents 91c6068 + 767cfd1 commit 9b936b5

File tree

4 files changed

+200
-34
lines changed

4 files changed

+200
-34
lines changed

source/loader/layers/sanitizer/asan_interceptor.cpp

Lines changed: 93 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ constexpr int kUsmDeviceRedzoneMagic = (char)0x81;
2424
constexpr int kUsmHostRedzoneMagic = (char)0x82;
2525
constexpr int kUsmSharedRedzoneMagic = (char)0x83;
2626
constexpr int kMemBufferRedzoneMagic = (char)0x84;
27+
constexpr int kDeviceGlobalRedZoneMagic = (char)0x85;
2728

2829
constexpr auto kSPIR_AsanShadowMemoryGlobalStart =
2930
"__AsanShadowMemoryGlobalStart";
@@ -36,6 +37,9 @@ constexpr auto kSPIR_DeviceType = "__DeviceType";
3637

3738
constexpr auto kSPIR_DeviceSanitizerReportMem = "__DeviceSanitizerReportMem";
3839

40+
constexpr auto kSPIR_AsanDeviceGlobalCount = "__AsanDeviceGlobalCount";
41+
constexpr auto kSPIR_AsanDeviceGlobalMetadata = "__AsanDeviceGlobalMetadata";
42+
3943
DeviceSanitizerReport SPIR_DeviceSanitizerReportMem;
4044

4145
uptr MemToShadow_CPU(uptr USM_SHADOW_BASE, uptr UPtr) {
@@ -78,6 +82,19 @@ ur_program_handle_t getProgram(ur_kernel_handle_t Kernel) {
7882
return Program;
7983
}
8084

85+
void getProgramDevices(ur_program_handle_t Program,
86+
std::vector<ur_device_handle_t> &Devices) {
87+
size_t PropSize;
88+
[[maybe_unused]] ur_result_t Result = context.urDdiTable.Program.pfnGetInfo(
89+
Program, UR_PROGRAM_INFO_DEVICES, 0, nullptr, &PropSize);
90+
assert(Result == UR_RESULT_SUCCESS);
91+
92+
Devices.resize(PropSize / sizeof(ur_device_handle_t));
93+
Result = context.urDdiTable.Program.pfnGetInfo(
94+
Program, UR_PROGRAM_INFO_DEVICES, PropSize, Devices.data(), nullptr);
95+
assert(Result == UR_RESULT_SUCCESS);
96+
}
97+
8198
size_t getLocalMemorySize(ur_device_handle_t Device) {
8299
size_t LocalMemorySize;
83100
[[maybe_unused]] auto Result = context.urDdiTable.Device.pfnGetInfo(
@@ -124,7 +141,7 @@ SanitizerInterceptor::~SanitizerInterceptor() {
124141
ur_result_t SanitizerInterceptor::allocateMemory(
125142
ur_context_handle_t Context, ur_device_handle_t Device,
126143
const ur_usm_desc_t *Properties, ur_usm_pool_handle_t Pool, size_t Size,
127-
void **ResultPtr, USMMemoryType Type) {
144+
void **ResultPtr, AllocType Type) {
128145
auto Alignment = Properties->align;
129146
assert(Alignment == 0 || IsPowerOfTwo(Alignment));
130147

@@ -147,13 +164,13 @@ ur_result_t SanitizerInterceptor::allocateMemory(
147164

148165
void *Allocated = nullptr;
149166

150-
if (Type == USMMemoryType::DEVICE) {
167+
if (Type == AllocType::DEVICE_USM) {
151168
UR_CALL(context.urDdiTable.USM.pfnDeviceAlloc(
152169
Context, Device, Properties, Pool, NeededSize, &Allocated));
153-
} else if (Type == USMMemoryType::HOST) {
170+
} else if (Type == AllocType::HOST_USM) {
154171
UR_CALL(context.urDdiTable.USM.pfnHostAlloc(Context, Properties, Pool,
155172
NeededSize, &Allocated));
156-
} else if (Type == USMMemoryType::SHARE) {
173+
} else if (Type == AllocType::SHARED_USM) {
157174
UR_CALL(context.urDdiTable.USM.pfnSharedAlloc(
158175
Context, Device, Properties, Pool, NeededSize, &Allocated));
159176
} else {
@@ -173,31 +190,31 @@ ur_result_t SanitizerInterceptor::allocateMemory(
173190

174191
*ResultPtr = reinterpret_cast<void *>(UserBegin);
175192

176-
auto AllocInfo = std::make_shared<USMAllocInfo>(
177-
USMAllocInfo{AllocBegin, UserBegin, UserEnd, NeededSize, Type});
193+
auto AI = std::make_shared<AllocInfo>(
194+
AllocInfo{AllocBegin, UserBegin, UserEnd, NeededSize, Type});
178195

179196
// For updating shadow memory
180197
if (DeviceInfo) { // device/shared USM
181198
std::scoped_lock<ur_shared_mutex> Guard(DeviceInfo->Mutex);
182-
DeviceInfo->AllocInfos.emplace_back(AllocInfo);
199+
DeviceInfo->AllocInfos.emplace_back(AI);
183200
} else { // host USM's AllocInfo needs to insert into all devices
184201
for (auto &pair : ContextInfo->DeviceMap) {
185202
auto DeviceInfo = pair.second;
186203
std::scoped_lock<ur_shared_mutex> Guard(DeviceInfo->Mutex);
187-
DeviceInfo->AllocInfos.emplace_back(AllocInfo);
204+
DeviceInfo->AllocInfos.emplace_back(AI);
188205
}
189206
}
190207

191208
// For memory release
192209
{
193210
std::scoped_lock<ur_shared_mutex> Guard(ContextInfo->Mutex);
194-
ContextInfo->AllocatedUSMMap[AllocBegin] = std::move(AllocInfo);
211+
ContextInfo->AllocatedUSMMap[AllocBegin] = std::move(AI);
195212
}
196213

197214
context.logger.info(
198215
"AllocInfos(AllocBegin={}, User={}-{}, NeededSize={}, Type={})",
199216
(void *)AllocBegin, (void *)UserBegin, (void *)UserEnd, NeededSize,
200-
Type);
217+
ToString(Type));
201218

202219
return UR_RESULT_SUCCESS;
203220
}
@@ -285,8 +302,8 @@ void SanitizerInterceptor::postLaunchKernel(ur_kernel_handle_t Kernel,
285302
KernelName = DemangleName(KernelName);
286303

287304
context.logger.always("\n====ERROR: DeviceSanitizer: {} on {}",
288-
DeviceSanitizerFormat(AH->ErrorType),
289-
DeviceSanitizerFormat(AH->MemoryType));
305+
ToString(AH->ErrorType),
306+
ToString(AH->MemoryType));
290307
context.logger.always(
291308
"{} of size {} at kernel <{}> LID({}, {}, {}) GID({}, "
292309
"{}, {})",
@@ -478,7 +495,7 @@ ur_result_t SanitizerInterceptor::enqueueMemSetShadow(
478495
/// ref: https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm#mapping
479496
ur_result_t SanitizerInterceptor::enqueueAllocInfo(
480497
ur_context_handle_t Context, ur_device_handle_t Device,
481-
ur_queue_handle_t Queue, std::shared_ptr<USMAllocInfo> &AllocInfo,
498+
ur_queue_handle_t Queue, std::shared_ptr<AllocInfo> &AllocInfo,
482499
ur_event_handle_t &LastEvent) {
483500
// Init zero
484501
UR_CALL(enqueueMemSetShadow(Context, Device, Queue, AllocInfo->AllocBegin,
@@ -499,18 +516,21 @@ ur_result_t SanitizerInterceptor::enqueueAllocInfo(
499516

500517
int ShadowByte;
501518
switch (AllocInfo->Type) {
502-
case USMMemoryType::HOST:
519+
case AllocType::HOST_USM:
503520
ShadowByte = kUsmHostRedzoneMagic;
504521
break;
505-
case USMMemoryType::DEVICE:
522+
case AllocType::DEVICE_USM:
506523
ShadowByte = kUsmDeviceRedzoneMagic;
507524
break;
508-
case USMMemoryType::SHARE:
525+
case AllocType::SHARED_USM:
509526
ShadowByte = kUsmSharedRedzoneMagic;
510527
break;
511-
case USMMemoryType::MEM_BUFFER:
528+
case AllocType::MEM_BUFFER:
512529
ShadowByte = kMemBufferRedzoneMagic;
513530
break;
531+
case AllocType::DEVICE_GLOBAL:
532+
ShadowByte = kDeviceGlobalRedZoneMagic;
533+
break;
514534
default:
515535
ShadowByte = 0xff;
516536
assert(false && "Unknow AllocInfo Type");
@@ -556,6 +576,62 @@ ur_result_t SanitizerInterceptor::updateShadowMemory(ur_queue_handle_t Queue) {
556576
return UR_RESULT_SUCCESS;
557577
}
558578

579+
ur_result_t
580+
SanitizerInterceptor::registerDeviceGlobals(ur_context_handle_t Context,
581+
ur_program_handle_t Program) {
582+
std::vector<ur_device_handle_t> Devices;
583+
getProgramDevices(Program, Devices);
584+
585+
for (auto Device : Devices) {
586+
ur_queue_handle_t Queue;
587+
ur_result_t Result = context.urDdiTable.Queue.pfnCreate(
588+
Context, Device, nullptr, &Queue);
589+
if (Result != UR_RESULT_SUCCESS) {
590+
context.logger.error("Failed to create command queue: {}", Result);
591+
return Result;
592+
}
593+
594+
uint64_t NumOfDeviceGlobal;
595+
Result = context.urDdiTable.Enqueue.pfnDeviceGlobalVariableRead(
596+
Queue, Program, kSPIR_AsanDeviceGlobalCount, true,
597+
sizeof(NumOfDeviceGlobal), 0, &NumOfDeviceGlobal, 0, nullptr,
598+
nullptr);
599+
if (Result == UR_RESULT_ERROR_INVALID_ARGUMENT) {
600+
context.logger.info("No device globals");
601+
continue;
602+
} else if (Result != UR_RESULT_SUCCESS) {
603+
context.logger.error("Device Global[{}] Read Failed: {}",
604+
kSPIR_AsanDeviceGlobalCount, Result);
605+
return Result;
606+
}
607+
608+
std::vector<DeviceGlobalInfo> GVInfos(NumOfDeviceGlobal);
609+
Result = context.urDdiTable.Enqueue.pfnDeviceGlobalVariableRead(
610+
Queue, Program, kSPIR_AsanDeviceGlobalMetadata, true,
611+
sizeof(DeviceGlobalInfo) * NumOfDeviceGlobal, 0, &GVInfos[0], 0,
612+
nullptr, nullptr);
613+
if (Result != UR_RESULT_SUCCESS) {
614+
context.logger.error("Device Global[{}] Read Failed: {}",
615+
kSPIR_AsanDeviceGlobalMetadata, Result);
616+
return Result;
617+
}
618+
619+
auto ContextInfo = getContextInfo(Context);
620+
auto DeviceInfo = ContextInfo->getDeviceInfo(Device);
621+
for (size_t i = 0; i < NumOfDeviceGlobal; i++) {
622+
auto AI = std::make_shared<AllocInfo>(AllocInfo{
623+
GVInfos[i].Addr, GVInfos[i].Addr,
624+
GVInfos[i].Addr + GVInfos[i].Size, GVInfos[i].SizeWithRedZone,
625+
AllocType::DEVICE_GLOBAL});
626+
627+
std::scoped_lock<ur_shared_mutex> Guard(DeviceInfo->Mutex);
628+
DeviceInfo->AllocInfos.emplace_back(AI);
629+
}
630+
}
631+
632+
return UR_RESULT_SUCCESS;
633+
}
634+
559635
ur_result_t SanitizerInterceptor::insertContext(ur_context_handle_t Context) {
560636
auto ContextInfo = std::make_shared<ur_sanitizer_layer::ContextInfo>();
561637

source/loader/layers/sanitizer/asan_interceptor.hpp

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,20 @@
2222

2323
namespace ur_sanitizer_layer {
2424

25-
enum USMMemoryType { DEVICE, SHARE, HOST, MEM_BUFFER };
25+
enum class AllocType : uint32_t {
26+
DEVICE_USM,
27+
SHARED_USM,
28+
HOST_USM,
29+
MEM_BUFFER,
30+
DEVICE_GLOBAL
31+
};
2632

27-
struct USMAllocInfo {
33+
struct AllocInfo {
2834
uptr AllocBegin;
2935
uptr UserBegin;
3036
uptr UserEnd;
3137
size_t AllocSize;
32-
USMMemoryType Type;
38+
AllocType Type;
3339
};
3440

3541
enum class DeviceType { UNKNOWN, CPU, GPU_PVC, GPU_DG2 };
@@ -42,7 +48,7 @@ struct DeviceInfo {
4248

4349
// Lock InitPool & AllocInfos
4450
ur_shared_mutex Mutex;
45-
std::vector<std::shared_ptr<USMAllocInfo>> AllocInfos;
51+
std::vector<std::shared_ptr<AllocInfo>> AllocInfos;
4652
};
4753

4854
struct QueueInfo {
@@ -64,7 +70,7 @@ struct ContextInfo {
6470
return QueueMap[Queue];
6571
}
6672

67-
std::shared_ptr<USMAllocInfo> getUSMAllocInfo(uptr Address) {
73+
std::shared_ptr<AllocInfo> getUSMAllocInfo(uptr Address) {
6874
std::shared_lock<ur_shared_mutex> Guard(Mutex);
6975
assert(AllocatedUSMMap.find(Address) != AllocatedUSMMap.end());
7076
return AllocatedUSMMap[Address];
@@ -78,7 +84,7 @@ struct ContextInfo {
7884
/// key: USMAllocInfo.AllocBegin
7985
/// value: USMAllocInfo
8086
/// Use AllocBegin as key can help to detect underflow pointer
81-
std::map<uptr, std::shared_ptr<USMAllocInfo>> AllocatedUSMMap;
87+
std::map<uptr, std::shared_ptr<AllocInfo>> AllocatedUSMMap;
8288
};
8389

8490
struct LaunchInfo {
@@ -95,6 +101,12 @@ struct LaunchInfo {
95101
~LaunchInfo();
96102
};
97103

104+
struct DeviceGlobalInfo {
105+
uptr Size;
106+
uptr SizeWithRedZone;
107+
uptr Addr;
108+
};
109+
98110
class SanitizerInterceptor {
99111
public:
100112
SanitizerInterceptor();
@@ -105,9 +117,12 @@ class SanitizerInterceptor {
105117
ur_device_handle_t Device,
106118
const ur_usm_desc_t *Properties,
107119
ur_usm_pool_handle_t Pool, size_t Size,
108-
void **ResultPtr, USMMemoryType Type);
120+
void **ResultPtr, AllocType Type);
109121
ur_result_t releaseMemory(ur_context_handle_t Context, void *Ptr);
110122

123+
ur_result_t registerDeviceGlobals(ur_context_handle_t Context,
124+
ur_program_handle_t Program);
125+
111126
ur_result_t preLaunchKernel(ur_kernel_handle_t Kernel,
112127
ur_queue_handle_t Queue,
113128
ur_event_handle_t &Event,
@@ -131,7 +146,7 @@ class SanitizerInterceptor {
131146
ur_result_t enqueueAllocInfo(ur_context_handle_t Context,
132147
ur_device_handle_t Device,
133148
ur_queue_handle_t Queue,
134-
std::shared_ptr<USMAllocInfo> &AlloccInfo,
149+
std::shared_ptr<AllocInfo> &AI,
135150
ur_event_handle_t &LastEvent);
136151

137152
/// Initialize Global Variables & Kernel Name at first Launch
@@ -163,4 +178,21 @@ class SanitizerInterceptor {
163178
bool m_ShadowMemInited;
164179
};
165180

181+
inline const char *ToString(AllocType Type) {
182+
switch (Type) {
183+
case AllocType::DEVICE_USM:
184+
return "Device USM";
185+
case AllocType::HOST_USM:
186+
return "Host USM";
187+
case AllocType::SHARED_USM:
188+
return "Shared USM";
189+
case AllocType::MEM_BUFFER:
190+
return "Memory Buffer";
191+
case AllocType::DEVICE_GLOBAL:
192+
return "Device Global";
193+
default:
194+
return "Unknown Type";
195+
}
196+
}
197+
166198
} // namespace ur_sanitizer_layer

source/loader/layers/sanitizer/device_sanitizer_report.hpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ enum class DeviceSanitizerMemoryType : int32_t {
3232
LOCAL,
3333
PRIVATE,
3434
MEM_BUFFER,
35+
DEVICE_GLOBAL,
3536
};
3637

3738
struct DeviceSanitizerReport {
@@ -58,26 +59,28 @@ struct DeviceSanitizerReport {
5859
bool IsRecover = false;
5960
};
6061

61-
inline const char *DeviceSanitizerFormat(DeviceSanitizerMemoryType MemoryType) {
62+
inline const char *ToString(DeviceSanitizerMemoryType MemoryType) {
6263
switch (MemoryType) {
6364
case DeviceSanitizerMemoryType::USM_DEVICE:
64-
return "USM Device Memory";
65+
return "Device USM";
6566
case DeviceSanitizerMemoryType::USM_HOST:
66-
return "USM Host Memory";
67+
return "Host USM";
6768
case DeviceSanitizerMemoryType::USM_SHARED:
68-
return "USM Shared Memory";
69+
return "Shared USM";
6970
case DeviceSanitizerMemoryType::LOCAL:
7071
return "Local Memory";
7172
case DeviceSanitizerMemoryType::PRIVATE:
7273
return "Private Memory";
7374
case DeviceSanitizerMemoryType::MEM_BUFFER:
7475
return "Memory Buffer";
76+
case DeviceSanitizerMemoryType::DEVICE_GLOBAL:
77+
return "Device Global";
7578
default:
7679
return "Unknown Memory";
7780
}
7881
}
7982

80-
inline const char *DeviceSanitizerFormat(DeviceSanitizerErrorType ErrorType) {
83+
inline const char *ToString(DeviceSanitizerErrorType ErrorType) {
8184
switch (ErrorType) {
8285
case DeviceSanitizerErrorType::OUT_OF_BOUNDS:
8386
return "out-of-bounds-access";

0 commit comments

Comments
 (0)