Skip to content

Commit 498d7b0

Browse files
committed
apply review feedback
copy inputs to SpecializationConstant to prevent dangling pointers
1 parent 8357c8b commit 498d7b0

3 files changed

Lines changed: 37 additions & 19 deletions

File tree

‎dpctl/program/_program.pyx‎

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ from cpython.buffer cimport (
3838
from cpython.bytes cimport PyBytes_FromStringAndSize
3939
from libc.stdint cimport uint32_t
4040
from libc.stdlib cimport free, malloc
41-
from libc.string cimport memcmp
41+
from libc.string cimport memcmp, memcpy
4242

4343
import warnings
4444

@@ -299,12 +299,10 @@ cdef class SpecializationConstant:
299299
integers, the first argument is interpreted as the number of bytes and
300300
the second argument is interpreted as a pointer to the data.
301301
302-
Note that when constructing from a buffer, the
303-
:class:`.SpecializationConstant`, shares memory with the original object.
304-
Modifications to the original object's data after construction will be
305-
reflected when the :class:`.SpecializationConstant` is used to create a
306-
:class:`.SyclKernelBundle`. This is not the case when constructing from a
307-
raw pointer, as the data is copied.
302+
Note that construction of the :class:`.SpecializationConstant` copies the
303+
input, so modifications made after construction of the
304+
:class:`.SpecializationConstant` will not be reflected in the
305+
:class:`.SyclKernelBundle`.
308306
309307
Args:
310308
spec_id (int):
@@ -320,11 +318,12 @@ cdef class SpecializationConstant:
320318
"""
321319

322320
cdef _spec_const _spec_const
323-
cdef Py_buffer _buffer
324321

325322
def __cinit__(self, spec_id, *args):
326323
cdef int ret_code = 0
327324
cdef object target_obj = None
325+
cdef Py_buffer _local_buffer
326+
cdef void *copied_data
328327

329328
if not isinstance(spec_id, numbers.Integral):
330329
raise TypeError(
@@ -349,16 +348,16 @@ cdef class SpecializationConstant:
349348
)
350349
elif isinstance(args[0], str):
351350
target_obj = np.ascontiguousarray(args[1], dtype=args[0])
351+
else:
352+
raise TypeError(
353+
"Invalid arguments."
354+
)
352355

353356
elif len(args) == 1:
354357
target_obj = args[0]
355358
if not PyObject_CheckBuffer(target_obj):
356359
# attempt to coerce to a numpy array
357360
target_obj = np.ascontiguousarray(target_obj)
358-
else:
359-
raise TypeError(
360-
"Invalid arguments."
361-
)
362361

363362
if isinstance(target_obj, np.ndarray):
364363
if target_obj.dtype.kind not in ("b", "i", "u", "f", "c"):
@@ -373,17 +372,30 @@ cdef class SpecializationConstant:
373372
)
374373

375374
ret_code = PyObject_GetBuffer(
376-
target_obj, &(self._buffer), PyBUF_SIMPLE | PyBUF_ANY_CONTIGUOUS
375+
target_obj, &(_local_buffer), PyBUF_SIMPLE | PyBUF_ANY_CONTIGUOUS
377376
)
378377
if ret_code != 0:
379378
raise ValueError(
380379
"Failed to get buffer view for the provided object."
381380
)
382-
self._spec_const.value = <void*>self._buffer.buf
383-
self._spec_const.size = <size_t>self._buffer.len
381+
382+
self._spec_const.size = <size_t>_local_buffer.len
383+
copied_data = malloc(self._spec_const.size)
384+
385+
if copied_data == NULL:
386+
PyBuffer_Release(&(_local_buffer))
387+
raise MemoryError(
388+
"Failed to allocate memory for specialization constant data."
389+
)
390+
391+
memcpy(copied_data, _local_buffer.buf, self._spec_const.size)
392+
self._spec_const.value = copied_data
393+
394+
PyBuffer_Release(&(_local_buffer))
384395

385396
def __dealloc__(self):
386-
PyBuffer_Release(&(self._buffer))
397+
if self._spec_const.value != NULL:
398+
free(<void*>self._spec_const.value)
387399

388400
def __repr__(self):
389401
return f"SpecializationConstant({self._spec_const.id})"

‎dpctl/program/utils/_utils.py‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ def parse_spirv_specializations(
106106

107107
if word_count == 0:
108108
raise ValueError(f"Invalid SPIR-V instruction at word index {i}")
109+
if i + word_count > len(words):
110+
raise ValueError(
111+
f"Invalid SPIR-V instruction at offset {i} (extends beyond "
112+
"buffer)"
113+
)
109114

110115
if opcode == SpirvOpCode.OpFunction:
111116
# everything following is not relevant to specialization constant
@@ -173,12 +178,14 @@ def parse_spirv_specializations(
173178
dtype_str = type_info["dtype"]
174179
raw_default = defaults.get(target_id)
175180
default_value = None
176-
if isinstance(raw_default, bytes):
181+
if isinstance(raw_default, bool):
182+
default_value = raw_default
183+
elif isinstance(raw_default, bytes) and dtype_str != "unknown_type":
177184
try:
178185
default_value = np.frombuffer(raw_default, dtype=dtype_str)[
179186
0
180187
].item()
181-
except Exception:
188+
except (ValueError, TypeError):
182189
default_value = None
183190

184191
result.append(

‎libsyclinterface/source/dpctl_sycl_kernel_bundle_interface.cpp‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,6 @@ _CreateKernelBundleWithIL_ze_impl(const context &SyclCtx,
503503
backend_traits<ze_be>::return_type<device> ZeDevice;
504504
ZeDevice = get_native<ze_be>(SyclDev);
505505

506-
// Specialization constants are not supported by DPCTL at the moment
507506
std::vector<std::uint32_t> spec_ids;
508507
std::vector<const void *> spec_values;
509508

0 commit comments

Comments
 (0)