Skip to content

Commit 0125279

Browse files
committed
fix: prevent double-close of IPC memory handle in MemoryIPCDevice
create_ipc_from_usm_pointer_size_qref(): Wrap the MemoryIPCDevice construction in try/except. On failure, null base._memory_ptr to signal that __dealloc__ already closed the handle. On success, null base._memory_ptr to prevent base's own dealloc from touching it. Also null _memory_ptr in the SyclQueueCreationError path so the caller knows it still owns the handle. IPCMemoryHandle.open(): Split the single try/except into two: - SyclQueue creation failure: handle not yet transferred, close it. - create_ipc_from_usm_pointer_size_qref raises ValueError: failed before construction (queue copy), handle not closed, close it. - Any other exception from construction: __dealloc__ already closed the handle, do NOT close again. Signed-off-by: Zhan Xue <zhan.xue@intel.com>
1 parent 3ec98e3 commit 0125279

2 files changed

Lines changed: 26 additions & 5 deletions

File tree

dpctl/memory/_memory.pyx

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -903,7 +903,7 @@ cdef class MemoryUSMDevice(_Memory):
903903

904904
cdef class MemoryIPCDevice(MemoryUSMDevice):
905905
"""
906-
Class representing emory object backed by an IPC-mapped USM device pointer.
906+
Class representing memory object backed by an IPC-mapped USM device pointer.
907907
908908
This class is not intended to be instantiated directly.
909909
"""
@@ -947,12 +947,22 @@ cdef class MemoryIPCDevice(MemoryUSMDevice):
947947
try:
948948
base.queue = SyclQueue._create(QRef_copy)
949949
except dpctl.SyclQueueCreationError as sqce:
950+
base._memory_ptr = NULL # caller retains ownership of USMRef
950951
raise ValueError(
951952
"SyclQueue object could not be created from "
952953
"copy of referenced queue"
953954
) from sqce
954955

955-
return MemoryIPCDevice(<object>base)
956+
try:
957+
result = MemoryIPCDevice(<object>base)
958+
except Exception:
959+
# If MemoryIPCDevice.__cinit__ failed after _cinit_other copied
960+
# _memory_ptr, the partial object's __dealloc__ already closed
961+
# the IPC handle. Null base to prevent any further action.
962+
base._memory_ptr = NULL
963+
raise
964+
base._memory_ptr = NULL # ownership fully transferred to result
965+
return result
956966

957967

958968
def as_usm_memory(obj):
@@ -1208,11 +1218,23 @@ cdef class IPCMemoryHandle:
12081218
cdef SyclQueue q
12091219
try:
12101220
q = dpctl.SyclQueue(context, device)
1221+
except Exception:
1222+
DPCTLIPCMem_CloseHandle(mapped_ptr, ctx_ref)
1223+
raise
1224+
1225+
try:
12111226
mem = MemoryIPCDevice.create_ipc_from_usm_pointer_size_qref(
12121227
mapped_ptr, nbytes, q.get_queue_ref())
1213-
except Exception:
1228+
except ValueError:
1229+
# Failed before MemoryIPCDevice construction (queue copy, etc).
1230+
# Handle was NOT closed — we still own it.
12141231
DPCTLIPCMem_CloseHandle(mapped_ptr, ctx_ref)
12151232
raise
1233+
except Exception:
1234+
# Failed during MemoryIPCDevice construction.
1235+
# MemoryIPCDevice.__dealloc__ already closed the IPC handle.
1236+
# Do NOT close again to avoid double-close (undefined behavior).
1237+
raise
12161238

12171239
return mem
12181240

libsyclinterface/include/syclinterface/dpctl_sycl_ipc_memory_interface.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ DPCTL_C_EXTERN_C_BEGIN
4242
* @brief Get an IPC memory handle for a USM device pointer.
4343
*
4444
* Wraps ``sycl::ext::oneapi::experimental::ipc::memory::get()``.
45-
* The returned handle bytes are copied out and the driver-side handle
46-
* resource is released (via ``put``) before returning.
45+
* The returned handle bytes are copied out.
4746
*
4847
* @param Ptr USM device pointer to export.
4948
* @param CRef Sycl context associated with the pointer.

0 commit comments

Comments
 (0)