Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ This release is compatible with NumPy 2.5.
* Fixed `__array_namespace_info__().devices()` and `.default_device()` to return Python array API compatible device objects [#2979](https://github.com/IntelPython/dpnp/pull/2979)
* Fixed `dpnp.interp` with an empty input array `x` to return an empty array with the correct dtype [#2985](https://github.com/IntelPython/dpnp/pull/2985)
* Fixed `dpnp.interp` returning `nan` when querying at an exact knot point whose adjacent `fp` value is `inf` [#2986](https://github.com/IntelPython/dpnp/pull/2986)
* Fixed missing strides validation in `dpnp.tensor.usm_ndarray` constructor when allocating new memory [#2927](https://github.com/IntelPython/dpnp/pull/2927)

### Security

Expand Down
49 changes: 31 additions & 18 deletions dpnp/tensor/_usmarray.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -378,20 +378,19 @@ cdef class usm_ndarray:
if (typenum < 0):
if typenum == -2:
raise ValueError(
"Data type '" + str(dtype) +
"' can only have native byteorder."
f"Data type '{dtype}' can only have native byteorder."
)
elif typenum == -1:
raise ValueError(
"Data type '" + str(dtype) + "' is not understood."
f"Data type '{dtype}' is not understood."
)
raise TypeError(
f"Expected string or a dtype object, got {type(dtype)}"
)
itemsize = type_bytesize(typenum)
if (itemsize < 1):
raise TypeError(
"dtype=" + np.dtype(dtype).name + " is not supported."
f"dtype={np.dtype(dtype).name} is not supported."
)
# allocate host C-arrays for shape, strides
err = _from_input_shape_strides(
Expand All @@ -406,11 +405,11 @@ cdef class usm_ndarray:
"array failed.")
elif err == ERROR_INCORRECT_ORDER:
raise ValueError(
"Unsupported order='{}' given. "
"Supported values are 'C' or 'F'.".format(order))
f"Unsupported order='{order}' given. "
"Supported values are 'C' or 'F'.")
elif err == ERROR_UNEXPECTED_STRIDES:
raise ValueError(
"strides={} is not understood".format(strides))
f"strides={strides} is not understood")
else:
raise InternalUSMArrayError(
" .. while processing shape and strides.")
Expand All @@ -421,6 +420,21 @@ cdef class usm_ndarray:
elif isinstance(buffer, (str, bytes)):
if isinstance(buffer, bytes):
buffer = buffer.decode("UTF-8")
if strides is not None and ary_min_displacement < 0:
self._cleanup()
raise ValueError(
f"strides={strides} result in a negative memory "
"displacement and are not allowed when allocating "
"new memory")
if strides is not None and (
(ary_max_displacement - ary_min_displacement + 1) > ary_nelems
):
self._cleanup()
raise ValueError(
f"strides={strides} is incompatible with "
f"shape={shape} when allocating new memory because "
"the memory footprint exceeds the number of elements"
)
_offset = -ary_min_displacement
if (buffer == "shared"):
_buffer = dpmem.MemoryUSMShared(ary_nbytes,
Expand All @@ -434,24 +448,24 @@ cdef class usm_ndarray:
else:
self._cleanup()
raise ValueError(
"buffer='{}' is not understood. "
f"buffer='{buffer}' is not understood. "
"Recognized values are 'device', 'shared', 'host', "
"an instance of `MemoryUSM*` object, or a usm_ndarray"
"".format(buffer)
)
elif isinstance(buffer, usm_ndarray):
if not buffer.flags.writable:
writable_flag = 0
_buffer = buffer.usm_data
else:
self._cleanup()
raise ValueError("buffer='{}' was not understood.".format(buffer))
raise ValueError(f"buffer='{buffer}' was not understood.")
if (shape_to_elem_count(nd, shape_ptr) > 0 and
(_offset + ary_min_displacement < 0 or
(_offset + ary_max_displacement + 1) * itemsize > _buffer.nbytes)):
self._cleanup()
raise ValueError(("buffer='{}' can not accommodate "
"the requested array.").format(buffer))
raise ValueError(
f"buffer='{buffer}' can not accommodate the requested array."
)
is_fp64 = (typenum == UAR_DOUBLE or typenum == UAR_CDOUBLE)
is_fp16 = (typenum == UAR_HALF)
if (is_fp64 or is_fp16):
Expand Down Expand Up @@ -640,9 +654,8 @@ cdef class usm_ndarray:
if (not isinstance(self.base_, dpmem._memory._Memory)):
raise InternalUSMArrayError(
"Invalid instance of usm_ndarray encountered. "
"Private field base_ has an unexpected type {}.".format(
type(self.base_)
)
"Private field base_ has an unexpected type "
f"{type(self.base_)}."
)
ary_iface = self.base_.__sycl_usm_array_interface__
mem_ptr = <char *>(<size_t> ary_iface["data"][0])
Expand Down Expand Up @@ -803,7 +816,7 @@ cdef class usm_ndarray:
self.strides_ = strides_ptr
else:
raise InternalUSMArrayError(
"Encountered in shape setter, error code {err}".format(err)
f"Encountered in shape setter, error code {err}"
)

@property
Expand Down Expand Up @@ -1905,7 +1918,7 @@ cdef api object UsmNDArray_MakeSimpleFromPtr(
cdef int itemsize = type_bytesize(typenum)
if (itemsize < 1):
raise ValueError(
"dtype with typenum=" + str(typenum) + " is not supported."
f"dtype with typenum={typenum} is not supported."
)
cdef size_t nbytes = (<size_t> itemsize) * nelems
cdef c_dpmem._Memory mobj
Expand Down Expand Up @@ -1961,7 +1974,7 @@ cdef api object UsmNDArray_MakeFromPtr(

if (itemsize < 1):
raise ValueError(
"dtype with typenum=" + str(typenum) + " is not supported."
f"dtype with typenum={typenum} is not supported."
)
if (nd < 0):
raise ValueError("Dimensionality must be non-negative")
Expand Down
16 changes: 13 additions & 3 deletions dpnp/tests/tensor/test_usm_ndarray_ctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,6 @@ def test_usm_ndarray_flags():
f = dpt.usm_ndarray((5, 0, 1), dtype="i4", strides=(1, 0, 1)).flags
assert f.fc
assert f.forc
assert not dpt.usm_ndarray(
(5, 1, 1), dtype="i4", strides=(2, 0, 1)
).flags.forc

x = dpt.empty(5, dtype="u2")
assert x.flags.writable is True
Expand Down Expand Up @@ -1085,6 +1082,19 @@ def test_ctor_invalid():
dpt.usm_ndarray((4,), dtype="u1", buffer=m, strides={"not": "valid"})


def test_ctor_invalid_strides():
try:
dpt.usm_ndarray((1,), dtype="i4")
except dpctl.SyclDeviceCreationError:
pytest.skip("No SYCL devices available")
# negative displacement
with pytest.raises(ValueError):
dpt.usm_ndarray((2, 3, 4), dtype="i4", strides=(-1, 1, 1))
# oversized memory footprint
with pytest.raises(ValueError):
dpt.usm_ndarray((2, 3, 4), dtype="i4", strides=(1, 16, 128))


def test_reshape():
try:
X = dpt.usm_ndarray((5, 5), "i4")
Expand Down
Loading