Skip to content

Commit b62b58d

Browse files
authored
[OpenMP] Fix crash with duplicate mapping on target directive (#146136)
OpenMP allows duplicate mappings, i.e. in OpenMP 6.0, 7.9.6 "map Clause": Two list items of the map clauses on the same construct must not share original storage unless one of the following is true: they are the same list item [or other omitted reasons]" Duplicate mappings can arise as a result of user-defined mapper processing (which I think is a separate bug, and is not addressed here), but also in straightforward cases such as: #pragma omp target map(tofrom: s.mem[0:10]) map(tofrom: s.mem[0:10]) Both these cases cause crashes at runtime at present, due to an unfortunate interaction between reference counting behaviour and shadow pointer handling for blocks. This is what happens: 1. The member "s.mem" is copied to the target 2. A shadow pointer is created, modifying the pointer on the target 3. The member "s.mem" is copied to the target again 4. The previous shadow pointer metadata is still present, so the runtime doesn't modify the target pointer a second time. The fix is to disable step 3 if we've already done step 2 for a given block that has the "is new" flag set.
1 parent 1f5f381 commit b62b58d

File tree

3 files changed

+78
-0
lines changed

3 files changed

+78
-0
lines changed

offload/libomptarget/OpenMP/Mapping.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,28 @@ TargetPointerResultTy MappingInfoTy::getTargetPointer(
326326
// data transfer.
327327
if (LR.TPR.TargetPointer && !LR.TPR.Flags.IsHostPointer && HasFlagTo &&
328328
(LR.TPR.Flags.IsNewEntry || HasFlagAlways) && Size != 0) {
329+
330+
// If we have something like:
331+
// #pragma omp target map(to: s.myarr[0:10]) map(to: s.myarr[0:10])
332+
// then we see two "new" mappings of the struct member s.myarr here --
333+
// and both have the "IsNewEntry" flag set, so trigger the copy to device
334+
// below. But, the shadow pointer is only initialised on the target for
335+
// the first copy, and the second copy clobbers it. So, this condition
336+
// avoids the (second) copy here if we have already set shadow pointer info.
337+
auto FailOnPtrFound = [HstPtrBegin, Size](ShadowPtrInfoTy &SP) {
338+
if (SP.HstPtrAddr >= HstPtrBegin &&
339+
SP.HstPtrAddr < (void *)((char *)HstPtrBegin + Size))
340+
return OFFLOAD_FAIL;
341+
return OFFLOAD_SUCCESS;
342+
};
343+
if (LR.TPR.getEntry()->foreachShadowPointerInfo(FailOnPtrFound) ==
344+
OFFLOAD_FAIL) {
345+
DP("Multiple new mappings of %" PRId64 " bytes detected (hst:" DPxMOD
346+
") -> (tgt:" DPxMOD ")\n",
347+
Size, DPxPTR(HstPtrBegin), DPxPTR(LR.TPR.TargetPointer));
348+
return std::move(LR.TPR);
349+
}
350+
329351
DP("Moving %" PRId64 " bytes (hst:" DPxMOD ") -> (tgt:" DPxMOD ")\n", Size,
330352
DPxPTR(HstPtrBegin), DPxPTR(LR.TPR.TargetPointer));
331353

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// clang-format off
2+
// RUN: %libomptarget-compilexx-generic -Wno-openmp-mapping && %libomptarget-run-generic
3+
4+
// clang-format on
5+
6+
#include <assert.h>
7+
8+
struct Inner {
9+
int *data;
10+
Inner(int size) { data = new int[size](); }
11+
~Inner() { delete[] data; }
12+
};
13+
14+
struct Outer {
15+
Inner i;
16+
Outer() : i(10) {}
17+
};
18+
19+
int main() {
20+
Outer o;
21+
#pragma omp target map(tofrom : o.i.data[0 : 10]) map(tofrom : o.i.data[0 : 10])
22+
{
23+
o.i.data[0] = 42;
24+
}
25+
assert(o.i.data[0] == 42);
26+
return 0;
27+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// clang-format off
2+
// RUN: %libomptarget-compilexx-generic -Wno-openmp-mapping && %libomptarget-run-generic
3+
4+
#include <assert.h>
5+
6+
// clang-format on
7+
8+
struct Inner {
9+
int *data;
10+
Inner(int size) { data = new int[size](); }
11+
~Inner() { delete[] data; }
12+
};
13+
#pragma omp declare mapper(Inner i) map(i, i.data[0 : 10])
14+
15+
struct Outer {
16+
Inner i;
17+
Outer() : i(10) {}
18+
};
19+
#pragma omp declare mapper(Outer o) map(o, o.i)
20+
21+
int main() {
22+
Outer o;
23+
#pragma omp target map(tofrom : o)
24+
{
25+
o.i.data[0] = 42;
26+
}
27+
assert(o.i.data[0] == 42);
28+
return 0;
29+
}

0 commit comments

Comments
 (0)