Skip to content

Commit 8b55062

Browse files
[SYCL] Fix the check for read-only host pointer during memobj creation (#2697)
Previously, whenever a native memory object was created, the original host pointer passed by the user was checked for being read-only, regardless of what host pointer was actually used at that point. This patch fixes the issue by assuming a writeable host pointer unless it's the one provided by the user. As a result, this fixes a double free issue that appeared with the following usage pattern: 1. Create a buffer with a const user pointer 2. Write-access it on host 3. Access it on a non-host device 4. Access it on host This error was caused by the allocation performed at step 2 being treated as read-only and, therefore, used with PI_MEM_FLAGS_HOST_PTR_COPY rather than PI_MEM_FLAGS_HOST_PTR_USE at step 3, while it was assumed otherwise during the release of this allocation. Signed-off-by: Sergey Semenov <[email protected]>
1 parent c62e237 commit 8b55062

File tree

3 files changed

+62
-23
lines changed

3 files changed

+62
-23
lines changed

sycl/source/detail/buffer_impl.cpp

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,26 @@ namespace sycl {
1616
namespace detail {
1717
void *buffer_impl::allocateMem(ContextImplPtr Context, bool InitFromUserData,
1818
void *HostPtr, RT::PiEvent &OutEventToWait) {
19+
// The host pointer for the allocation can be provided in 2 ways:
20+
// 1. Initialize the allocation from user data. Check if the user pointer is
21+
// read-only.
22+
// 2. Use a HostPtr allocated by the runtime. Assume any such pointer to be
23+
// read-write.
24+
bool HostPtrReadOnly = false;
25+
if (InitFromUserData) {
26+
assert(!HostPtr && "Cannot init from user data and reuse host ptr provided "
27+
"simultaneously");
28+
HostPtr = BaseT::getUserPtr();
29+
HostPtrReadOnly = BaseT::MHostPtrReadOnly;
30+
}
1931

20-
assert(!(InitFromUserData && HostPtr) &&
21-
"Cannot init from user data and reuse host ptr provided "
22-
"simultaneously");
23-
24-
void *UserPtr = InitFromUserData ? BaseT::getUserPtr() : HostPtr;
25-
26-
assert(!(nullptr == UserPtr && BaseT::useHostPtr() && Context->is_host()) &&
27-
"Internal error. Allocating memory on the host "
28-
"while having use_host_ptr property");
32+
assert(!(nullptr == HostPtr && BaseT::useHostPtr() && Context->is_host()) &&
33+
"Internal error. Allocating memory on the host "
34+
"while having use_host_ptr property");
2935

3036
return MemoryManager::allocateMemBuffer(
31-
std::move(Context), this, UserPtr, BaseT::MHostPtrReadOnly,
32-
BaseT::getSize(), BaseT::MInteropEvent, BaseT::MInteropContext, MProps,
33-
OutEventToWait);
37+
std::move(Context), this, HostPtr, HostPtrReadOnly, BaseT::getSize(),
38+
BaseT::MInteropEvent, BaseT::MInteropContext, MProps, OutEventToWait);
3439
}
3540
} // namespace detail
3641
} // namespace sycl

sycl/source/detail/image_impl.cpp

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -307,25 +307,31 @@ template <int Dimensions>
307307
void *image_impl<Dimensions>::allocateMem(ContextImplPtr Context,
308308
bool InitFromUserData, void *HostPtr,
309309
RT::PiEvent &OutEventToWait) {
310+
// The host pointer for the allocation can be provided in 2 ways:
311+
// 1. Initialize the allocation from user data. Check if the user pointer is
312+
// read-only.
313+
// 2. Use a HostPtr allocated by the runtime. Assume any such pointer to be
314+
// read-write.
315+
bool HostPtrReadOnly = false;
316+
if (InitFromUserData) {
317+
assert(!HostPtr && "Cannot init from user data and reuse host ptr provided "
318+
"simultaneously");
319+
HostPtr = BaseT::getUserPtr();
320+
HostPtrReadOnly = BaseT::MHostPtrReadOnly;
321+
}
310322

311-
assert(!(InitFromUserData && HostPtr) &&
312-
"Cannot init from user data and reuse host ptr provided "
313-
"simultaneously");
314-
315-
void *UserPtr = InitFromUserData ? BaseT::getUserPtr() : HostPtr;
316-
317-
RT::PiMemImageDesc Desc = getImageDesc(UserPtr != nullptr);
318-
assert(checkImageDesc(Desc, Context, UserPtr) &&
323+
RT::PiMemImageDesc Desc = getImageDesc(HostPtr != nullptr);
324+
assert(checkImageDesc(Desc, Context, HostPtr) &&
319325
"The check an image desc failed.");
320326

321327
RT::PiMemImageFormat Format = getImageFormat();
322328
assert(checkImageFormat(Format, Context) &&
323329
"The check an image format failed.");
324330

325331
return MemoryManager::allocateMemImage(
326-
std::move(Context), this, UserPtr, BaseT::MHostPtrReadOnly,
327-
BaseT::getSize(), Desc, Format, BaseT::MInteropEvent,
328-
BaseT::MInteropContext, MProps, OutEventToWait);
332+
std::move(Context), this, HostPtr, HostPtrReadOnly, BaseT::getSize(),
333+
Desc, Format, BaseT::MInteropEvent, BaseT::MInteropContext, MProps,
334+
OutEventToWait);
329335
}
330336

331337
template <int Dimensions>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %clangxx -fsycl -fsycl-targets=%sycl_triple %s -o %t.out
2+
// RUN: %CPU_RUN_PLACEHOLDER SYCL_PI_TRACE=-1 %t.out 2>&1 %CPU_CHECK_PLACEHOLDER
3+
4+
#include <CL/sycl.hpp>
5+
6+
class Foo;
7+
using namespace cl::sycl;
8+
int main() {
9+
const int BufVal = 42;
10+
buffer<int, 1> Buf{&BufVal, range<1>(1)};
11+
queue Q;
12+
13+
{
14+
// This should trigger memory allocation on host since the pointer passed by
15+
// the user is read-only.
16+
auto BufAcc = Buf.get_access<access::mode::write>();
17+
}
18+
19+
Q.submit([&](handler &Cgh) {
20+
// Now that we have a read-write host allocation, check that the native
21+
// buffer is created with the PI_MEM_FLAGS_HOST_PTR_USE flag.
22+
// CHECK: piMemBufferCreate
23+
// CHECK-NEXT: {{.*}} : {{.*}}
24+
// CHECK-NEXT: {{.*}} : 9
25+
auto BufAcc = Buf.get_access<access::mode::read>(Cgh);
26+
Cgh.single_task<Foo>([=]() { int A = BufAcc[0]; });
27+
});
28+
}

0 commit comments

Comments
 (0)