Skip to content

Commit 5accf42

Browse files
EthanLuisMcDonoughjdoerfert
authored andcommitted
GPU Sanitizer support for global variables
This commit extends GPU sanitizer support to global variables. Shadow variables that store the fake pointer values are added for each user-defined global. Right now, globals are registered by the host and de-allocated by the device, but this is expected to change in the future. The device-side allocation function is in the instrumentation pass, but it's commented out for now. Global variable references are rewritten as load instructions that get their respective fake pointer from the shadow globals.
1 parent 2521a3b commit 5accf42

File tree

12 files changed

+469
-34
lines changed

12 files changed

+469
-34
lines changed

llvm/lib/Transforms/Instrumentation/GPUSan.cpp

Lines changed: 312 additions & 18 deletions
Large diffs are not rendered by default.

offload/DeviceRTL/src/Sanitizer.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ template <AllocationKind AK> struct AllocationTracker {
7979

8080
[[clang::disable_sanitizer_instrumentation]] static _AS_PTR(void, AK)
8181
create(_AS_PTR(void, AK) Start, uint64_t Length, int64_t AllocationId,
82-
uint64_t Slot, int64_t SourceId, uint64_t PC) {
82+
int64_t Slot, int64_t SourceId, uint64_t PC) {
8383
if constexpr (SanitizerConfig<AK>::OFFSET_BITS < 64)
8484
if (OMP_UNLIKELY(Length >= (1UL << (SanitizerConfig<AK>::OFFSET_BITS))))
8585
__sanitizer_trap_info_ptr->exceedsAllocationLength<AK>(
@@ -90,6 +90,8 @@ template <AllocationKind AK> struct AllocationTracker {
9090
auto &Cnt = AllocArr.Cnt;
9191
if constexpr (AK == AllocationKind::LOCAL)
9292
Slot = ++Cnt;
93+
if (Slot == -1)
94+
Slot = ++Cnt;
9395

9496
uint64_t NumSlots = SanitizerConfig<AK>::SLOTS;
9597
if (OMP_UNLIKELY(Slot >= NumSlots))
@@ -246,10 +248,10 @@ extern "C" {
246248
[[clang::disable_sanitizer_instrumentation, gnu::flatten, gnu::always_inline,
247249
gnu::used, gnu::retain]] _AS_PTR(void, AllocationKind::GLOBAL)
248250
ompx_new_global(_AS_PTR(void, AllocationKind::GLOBAL) Start,
249-
uint64_t Length, int64_t AllocationId, uint32_t Slot,
250-
int64_t SourceId, uint64_t PC) {
251+
uint64_t Length, int64_t AllocationId, int64_t SourceId,
252+
uint64_t PC) {
251253
return AllocationTracker<AllocationKind::GLOBAL>::create(
252-
Start, Length, AllocationId, Slot, SourceId, PC);
254+
Start, Length, AllocationId, -1, SourceId, PC);
253255
}
254256
[[clang::disable_sanitizer_instrumentation, gnu::flatten, gnu::always_inline,
255257
gnu::used, gnu::retain]] void
@@ -260,13 +262,13 @@ __sanitizer_register_host(_AS_PTR(void, AllocationKind::GLOBAL) Start,
260262
}
261263
[[clang::disable_sanitizer_instrumentation, gnu::flatten, gnu::always_inline,
262264
gnu::used, gnu::retain]] void *
263-
ompx_new(void *Start, uint64_t Length, int64_t AllocationId, uint32_t Slot,
264-
int64_t SourceId, uint64_t PC) {
265+
ompx_new(void *Start, uint64_t Length, int64_t AllocationId, int64_t SourceId,
266+
uint64_t PC) {
265267
if (REAL_PTR_IS_LOCAL(Start))
266268
return (void *)ompx_new_local((_AS_PTR(void, AllocationKind::LOCAL))Start,
267269
Length, AllocationId, SourceId, PC);
268270
return (void *)ompx_new_global((_AS_PTR(void, AllocationKind::GLOBAL))Start,
269-
Length, AllocationId, Slot, SourceId, PC);
271+
Length, AllocationId, SourceId, PC);
270272
}
271273
[[clang::disable_sanitizer_instrumentation, gnu::flatten, gnu::always_inline,
272274
gnu::used, gnu::retain]] void

offload/plugins-nextgen/common/include/PluginInterface.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,8 @@ struct GPUSanTy {
678678
void addGPUSanNewFn(GenericKernelTy &GK) { NewFns.push_back(&GK); }
679679
void addGPUSanFreeFn(GenericKernelTy &GK) { FreeFns.push_back(&GK); }
680680
void checkAndReportError();
681+
Error transferFakePtrToDevice(const char *GlobalName, void *FakeHstPtr,
682+
SmallVector<DeviceImageTy *> &Images);
681683

682684
private:
683685
uint32_t SlotCnt = SanitizerConfig<AllocationKind::GLOBAL>::SLOTS - 1;
@@ -823,6 +825,13 @@ struct GenericDeviceTy : public DeviceAllocatorTy {
823825
return PinnedAllocs.unlockUnmappedHostBuffer(HstPtr);
824826
}
825827

828+
/// Transfers a fake pointer to its respective shadow variable to prevent
829+
/// double initializing GPUSan shadow constants. Only runs if GPUSan is
830+
/// enabled
831+
Error transferFakePtrToDevice(const char *GlobalName, void *FakeHstPtr) {
832+
return GPUSan.transferFakePtrToDevice(GlobalName, FakeHstPtr, LoadedImages);
833+
}
834+
826835
/// Check whether the host buffer with address \p HstPtr is pinned by the
827836
/// underlying vendor-specific runtime (if any). Retrieve the host pointer,
828837
/// the device accessible pointer and the size of the original pinned buffer.

offload/plugins-nextgen/common/src/PluginInterface.cpp

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2425,12 +2425,12 @@ void GPUSanTy::checkAndReportError() {
24252425
case SanitizerTrapInfoTy::None:
24262426
llvm_unreachable("Unexpected exception");
24272427
case SanitizerTrapInfoTy::ExceedsLength:
2428-
fprintf(stderr, "%sERROR: OffloadSanitizer %s\n%s", Red(), "exceeds length",
2429-
Default());
2428+
fprintf(stderr, "%sERROR: OffloadSanitizer %s %d\n%s", Red(),
2429+
"exceeds length", STI->PtrSlot, Default());
24302430
break;
24312431
case SanitizerTrapInfoTy::ExceedsSlots:
2432-
fprintf(stderr, "%sERROR: OffloadSanitizer %s\n%s", Red(), "exceeds slots",
2433-
Default());
2432+
fprintf(stderr, "%sERROR: OffloadSanitizer %s %d\n%s", Red(),
2433+
"exceeds slots", STI->PtrSlot, Default());
24342434
break;
24352435
case SanitizerTrapInfoTy::PointerOutsideAllocation:
24362436
fprintf(stderr, "%sERROR: OffloadSanitizer %s : %p : %i %lu (%s)\n%s",
@@ -2449,8 +2449,8 @@ void GPUSanTy::checkAndReportError() {
24492449
DiagnoseAccess("use-after-free");
24502450
break;
24512451
case SanitizerTrapInfoTy::MemoryLeak:
2452-
fprintf(stderr, "%sERROR: OffloadSanitizer %s\n%s", Red(), "memory leak",
2453-
Default());
2452+
fprintf(stderr, "%sERROR: OffloadSanitizer memory leak at slot %d\n%s",
2453+
Red(), STI->PtrSlot, Default());
24542454
break;
24552455
case SanitizerTrapInfoTy::GarbagePointer:
24562456
DiagnoseAccess("garbage-pointer");
@@ -2459,6 +2459,27 @@ void GPUSanTy::checkAndReportError() {
24592459
fflush(stderr);
24602460
}
24612461

2462+
Error GPUSanTy::transferFakePtrToDevice(const char *GlobalName,
2463+
void *FakeHstPtr,
2464+
SmallVector<DeviceImageTy *> &Images) {
2465+
if (!FakeHstPtr)
2466+
return Plugin::success();
2467+
2468+
std::string ShadowName("__san.global.");
2469+
ShadowName.append(GlobalName);
2470+
2471+
GenericGlobalHandlerTy &GHandler = Device.Plugin.getGlobalHandler();
2472+
GlobalTy ShadowGlobal(ShadowName, sizeof(void *), &FakeHstPtr);
2473+
2474+
int imgCount = 0;
2475+
for (auto Img : Images) {
2476+
if (GHandler.isSymbolInImage(Device, *Img, ShadowName))
2477+
return GHandler.writeGlobalToDevice(Device, *Img, ShadowGlobal);
2478+
}
2479+
2480+
return Plugin::error("Shadow global for '%s' not found", GlobalName);
2481+
}
2482+
24622483
bool llvm::omp::target::plugin::libomptargetSupportsRPC() {
24632484
#ifdef LIBOMPTARGET_RPC_SUPPORT
24642485
return true;

offload/src/PluginManager.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,11 @@ static int loadImagesOntoDevice(DeviceTy &Device) {
450450
CurrHostEntry->size,
451451
Entry->FakeTgtPtrBegin))
452452
return OFFLOAD_FAIL;
453+
454+
auto &DeviceInterface = Device.RTL->getDevice(DeviceId);
455+
if (DeviceInterface.transferFakePtrToDevice(CurrHostEntry->name,
456+
Entry->FakeTgtPtrBegin))
457+
return OFFLOAD_FAIL;
453458
}
454459
}
455460
Device.setHasPendingImages(false);

offload/test/sanitizer/global_null.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// clang-format off
22
// RUN: %libomptarget-compileopt-generic -fsanitize=offload
3-
// RUN: not %libomptarget-run-generic 2>&1 > %t.out
3+
// RUN: not %libomptarget-run-generic 2> %t.out
44
// RUN: %fcheck-generic --check-prefixes=CHECK < %t.out
55
// clang-format on
66

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %libomptarget-compileopt-generic -g -fsanitize=offload
2+
// RUN: not %libomptarget-run-generic 2> %t.out
3+
// RUN: %fcheck-generic --check-prefixes=CHECK < %t.out
4+
5+
// UNSUPPORTED: aarch64-unknown-linux-gnu
6+
// UNSUPPORTED: aarch64-unknown-linux-gnu-LTO
7+
// UNSUPPORTED: x86_64-pc-linux-gnu
8+
// UNSUPPORTED: x86_64-pc-linux-gnu-LTO
9+
// UNSUPPORTED: s390x-ibm-linux-gnu
10+
// UNSUPPORTED: s390x-ibm-linux-gnu-LTO
11+
12+
#include <omp.h>
13+
#include <stdio.h>
14+
15+
int global_arr[3] = {1, 2, 3};
16+
#pragma omp declare target(global_arr)
17+
18+
int main() {
19+
#pragma omp target
20+
{
21+
// CHECK: is located 12 bytes inside of a 12-byte region
22+
for (int i = 0; i < 4; i++) {
23+
global_arr[i] *= 4;
24+
}
25+
}
26+
return 0;
27+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %libomptarget-compileopt-generic -g -fsanitize=offload
2+
// RUN: %libomptarget-run-generic
3+
4+
// UNSUPPORTED: aarch64-unknown-linux-gnu
5+
// UNSUPPORTED: aarch64-unknown-linux-gnu-LTO
6+
// UNSUPPORTED: x86_64-pc-linux-gnu
7+
// UNSUPPORTED: x86_64-pc-linux-gnu-LTO
8+
// UNSUPPORTED: s390x-ibm-linux-gnu
9+
// UNSUPPORTED: s390x-ibm-linux-gnu-LTO
10+
11+
#include <omp.h>
12+
#include <stdio.h>
13+
14+
int global_arr[3] = {1, 2, 3};
15+
#pragma omp declare target(global_arr)
16+
17+
int main() {
18+
#pragma omp target
19+
{
20+
for (int i = 0; i < 3; i++) {
21+
global_arr[i] *= 4;
22+
}
23+
global_arr[1] = 22;
24+
}
25+
return 0;
26+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %libomptarget-compileopt-generic -g -fsanitize=offload
2+
// RUN: not %libomptarget-run-generic 2> %t.out
3+
// RUN: %fcheck-generic --check-prefixes=CHECK < %t.out
4+
5+
// UNSUPPORTED: aarch64-unknown-linux-gnu
6+
// UNSUPPORTED: aarch64-unknown-linux-gnu-LTO
7+
// UNSUPPORTED: x86_64-pc-linux-gnu
8+
// UNSUPPORTED: x86_64-pc-linux-gnu-LTO
9+
// UNSUPPORTED: s390x-ibm-linux-gnu
10+
// UNSUPPORTED: s390x-ibm-linux-gnu-LTO
11+
12+
#include <omp.h>
13+
#include <stdio.h>
14+
15+
int global_arr[3] = {1, 2, 3};
16+
#pragma omp declare target(global_arr)
17+
18+
int main() {
19+
#pragma omp target
20+
{
21+
// CHECK: is located 20 bytes inside of a 12-byte region
22+
global_arr[5] = 27;
23+
}
24+
return 0;
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %libomptarget-compileopt-generic -g -fsanitize=offload
2+
// RUN: %libomptarget-run-generic
3+
4+
// UNSUPPORTED: aarch64-unknown-linux-gnu
5+
// UNSUPPORTED: aarch64-unknown-linux-gnu-LTO
6+
// UNSUPPORTED: x86_64-pc-linux-gnu
7+
// UNSUPPORTED: x86_64-pc-linux-gnu-LTO
8+
// UNSUPPORTED: s390x-ibm-linux-gnu
9+
// UNSUPPORTED: s390x-ibm-linux-gnu-LTO
10+
11+
#include <omp.h>
12+
#include <stdio.h>
13+
14+
int global1 = 0;
15+
int global2 = -1;
16+
#pragma omp declare target(global1, global2)
17+
18+
int main() {
19+
#pragma omp target
20+
{
21+
global1 = 72;
22+
global2 = global1 + 75;
23+
}
24+
return 0;
25+
}

offload/test/sanitizer/heap_null.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// clang-format off
22
// RUN: %libomptarget-compileopt-generic -fsanitize=offload
3-
// RUN: not %libomptarget-run-generic 2>&1 > %t.out
3+
// RUN: not %libomptarget-run-generic 2> %t.out
44
// RUN: %fcheck-generic --check-prefixes=CHECK < %t.out
55
// clang-format on
66

offload/test/sanitizer/heap_random.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// clang-format off
22
// RUN: %libomptarget-compileopt-generic -fsanitize=offload
3-
// RUN: not %libomptarget-run-generic 2>&1 > %t.out
3+
// RUN: not %libomptarget-run-generic 2> %t.out
44
// RUN: %fcheck-generic --check-prefixes=CHECK < %t.out
55
// clang-format on
66

@@ -19,4 +19,5 @@ int main(void) {
1919
int *Random = &X;
2020
#pragma omp target
2121
{ *Random = 99; }
22+
// CHECK: 0x{{[a-f0-9]*}} is located {{[0-9]*}} bytes inside
2223
}

0 commit comments

Comments
 (0)