From fb87c0366783968c5c73e092116bd709f4035005 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 11 Mar 2026 12:22:52 +0100 Subject: [PATCH 1/8] Creates a new instance and sets the ptr attribute in all cases --- dpnp/memory/_memory.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/dpnp/memory/_memory.py b/dpnp/memory/_memory.py index f978c5e50db2..7e75d331a23c 100644 --- a/dpnp/memory/_memory.py +++ b/dpnp/memory/_memory.py @@ -98,13 +98,14 @@ def create_data(x): usm_data = x.usm_data if isinstance(usm_data, tuple(dispatch.values())): - return usm_data - - cls = dispatch.get(type(usm_data), None) - if cls: - data = cls(usm_data) - # `ptr` is expecting to point at the start of the array's data, - # while `usm_data._pointer` is a pointer at the start of memory buffer - data.ptr = x._pointer - return data - raise TypeError(f"Expected USM memory, but got {type(usm_data)}") + cls = usm_data.__class__ + else: + cls = dispatch.get(type(usm_data), None) + if cls is None: + raise TypeError(f"Expected USM memory, but got {type(usm_data)}") + + data = cls(usm_data) + # `ptr` is expecting to point at the start of the array's data, + # while `usm_data._pointer` is a pointer at the start of memory buffer + data.ptr = x._pointer + return data From 6a4df2a03d2338cedea6ade1be0c22bb81a2355f Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 11 Mar 2026 12:44:35 +0100 Subject: [PATCH 2/8] Add more comments to each implementation step --- dpnp/memory/_memory.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dpnp/memory/_memory.py b/dpnp/memory/_memory.py index 7e75d331a23c..fc3088b6a893 100644 --- a/dpnp/memory/_memory.py +++ b/dpnp/memory/_memory.py @@ -98,13 +98,17 @@ def create_data(x): usm_data = x.usm_data if isinstance(usm_data, tuple(dispatch.values())): + # usm_data is already an instance of MemoryUSM class cls = usm_data.__class__ + elif (cls := dispatch.get(type(usm_data))) is not None: + pass # cls is set else: - cls = dispatch.get(type(usm_data), None) - if cls is None: - raise TypeError(f"Expected USM memory, but got {type(usm_data)}") + raise TypeError(f"Expected USM memory, but got {type(usm_data)}") + # create a new instance each time since usm_data might be a view + # of another array data = cls(usm_data) + # `ptr` is expecting to point at the start of the array's data, # while `usm_data._pointer` is a pointer at the start of memory buffer data.ptr = x._pointer From 622876545b1a92ff47976e482a4689fd0a79d25e Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 11 Mar 2026 13:26:13 +0100 Subject: [PATCH 3/8] Add tests to cover the issue --- dpnp/tests/test_memory.py | 59 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/dpnp/tests/test_memory.py b/dpnp/tests/test_memory.py index 1bc0da8c1535..ea88f707669e 100644 --- a/dpnp/tests/test_memory.py +++ b/dpnp/tests/test_memory.py @@ -42,3 +42,62 @@ def test_view_non_zero_offset(self): pl = dpnp.ndarray((n, m), dtype=a.dtype, buffer=sl) assert pl.data.ptr == sl.data.ptr assert a.data.ptr != sl.data.ptr + + def test_slices_2d(self): + # Create 2D array and verify slices have different pointers + a = dpnp.arange(12, dtype=float).reshape(3, 4) + + # Each row should have a different pointer + row0_ptr = a[0].data.ptr + row1_ptr = a[1].data.ptr + row2_ptr = a[2].data.ptr + + assert ( + row0_ptr != row1_ptr + ), "a[0] and a[1] should have different pointers" + assert ( + row1_ptr != row2_ptr + ), "a[1] and a[2] should have different pointers" + + # Check byte offsets match expected stride + stride = a.strides[0] # stride between rows in bytes + assert row1_ptr - row0_ptr == stride + assert row2_ptr - row1_ptr == stride + + def test_slices_multidimensional(self): + # 3D array + a = dpnp.zeros((5, 10, 20), dtype=dpnp.int32) + + # Different slices along first axis should have different pointers + slice0_ptr = a[0].data.ptr + slice1_ptr = a[1].data.ptr + + assert slice0_ptr != slice1_ptr + assert slice1_ptr - slice0_ptr == a.strides[0] + + def test_repeated_access(self): + a = dpnp.arange(20).reshape(4, 5) + + # Multiple accesses to same slice should give same ptr value + ptr1 = a[2].data.ptr + ptr2 = a[2].data.ptr + + assert ptr1 == ptr2, "Same slice should have consistent ptr value" + + # But different slices should have different ptrs + assert a[0].data.ptr != a[2].data.ptr + + def test_array_on_view_with_slicing(self): + # Original array + a = dpnp.arange(24, dtype=dpnp.float32).reshape(6, 4) + + # Create view using slicing + view = a[2:5] + + # Construct new array from view + new_arr = dpnp.ndarray(view.shape, dtype=view.dtype, buffer=view) + + # Pointers should match + assert new_arr.data.ptr == view.data.ptr + # And should be different from base array + assert new_arr.data.ptr != a.data.ptr From 15ed605e16469b9ca9e9e5ebc36fceb6163c33cc Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 11 Mar 2026 13:27:51 +0100 Subject: [PATCH 4/8] Update comment in create_data --- dpnp/memory/_memory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpnp/memory/_memory.py b/dpnp/memory/_memory.py index fc3088b6a893..70d93c04d6a5 100644 --- a/dpnp/memory/_memory.py +++ b/dpnp/memory/_memory.py @@ -98,7 +98,7 @@ def create_data(x): usm_data = x.usm_data if isinstance(usm_data, tuple(dispatch.values())): - # usm_data is already an instance of MemoryUSM class + # usm_data is already an instance of MemoryUSM class cls = usm_data.__class__ elif (cls := dispatch.get(type(usm_data))) is not None: pass # cls is set From b75ed8e779f64bbb7425d6f4b8edc640c700c65a Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 11 Mar 2026 13:34:41 +0100 Subject: [PATCH 5/8] Add PR to the changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61cde1ddfefc..b6f419f215c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,7 @@ Also, that release drops support for Python 3.9, making Python 3.10 the minimum * Resolved an issue causing `dpnp.linspace` to return an incorrect output shape when inputs were passed as arrays [#2712](https://github.com/IntelPython/dpnp/pull/2712) * Resolved an issue where `dpnp` always returns the base allocation pointer, when the view start is expected [#2651](https://github.com/IntelPython/dpnp/pull/2651) * Fixed an issue causing an exception in `dpnp.geomspace` and `dpnp.logspace` when called with explicit `device` keyword but any input array is allocated on another device [#2723](https://github.com/IntelPython/dpnp/pull/2723) +* Fixed `.data.ptr` property on array views to correctly return the pointer to the view's data location instead of the base allocation pointer [#2812](https://github.com/IntelPython/dpnp/pull/2812) ### Security From cb21052dd16fae7ee6dbca02729a547fd15d5bb1 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 11 Mar 2026 14:28:12 +0100 Subject: [PATCH 6/8] Update test_slices_2d to pass on a device without fp64 --- dpnp/tests/test_memory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpnp/tests/test_memory.py b/dpnp/tests/test_memory.py index ea88f707669e..80d75f32a437 100644 --- a/dpnp/tests/test_memory.py +++ b/dpnp/tests/test_memory.py @@ -45,7 +45,7 @@ def test_view_non_zero_offset(self): def test_slices_2d(self): # Create 2D array and verify slices have different pointers - a = dpnp.arange(12, dtype=float).reshape(3, 4) + a = dpnp.arange(12, dtype=dpnp.float32).reshape(3, 4) # Each row should have a different pointer row0_ptr = a[0].data.ptr From 080764e7b7592c7537d242e1ce6c5beb2834cf44 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 16 Mar 2026 11:27:17 +0100 Subject: [PATCH 7/8] Combine tests without explicit dpm.create_data call as separate class --- dpnp/tests/test_memory.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dpnp/tests/test_memory.py b/dpnp/tests/test_memory.py index 80d75f32a437..a4753126f2fd 100644 --- a/dpnp/tests/test_memory.py +++ b/dpnp/tests/test_memory.py @@ -27,6 +27,8 @@ def test_wrong_usm_data(self): with pytest.raises(TypeError): dpm.create_data(d) + +class TestNdarray: def test_ndarray_from_data(self): a = dpnp.empty(5) b = dpnp.ndarray(a.shape, buffer=a.data) From 4bba2f297e5318ef0b208e2f18ff71f933c8e7ed Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 16 Mar 2026 11:34:53 +0100 Subject: [PATCH 8/8] Add more specific tests with direct call of dpm.create_data --- dpnp/tests/test_memory.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/dpnp/tests/test_memory.py b/dpnp/tests/test_memory.py index a4753126f2fd..6a3d6ac5afae 100644 --- a/dpnp/tests/test_memory.py +++ b/dpnp/tests/test_memory.py @@ -27,6 +27,39 @@ def test_wrong_usm_data(self): with pytest.raises(TypeError): dpm.create_data(d) + def test_dpctl_view(self): + a = dpt.arange(10) + view = a[3:] + + data = dpm.create_data(view) + assert data.ptr == view._pointer + + def test_dpctl_different_views(self): + a = dpt.reshape(dpt.arange(12), (3, 4)) + + data0 = dpm.create_data(a[0]) + data1 = dpm.create_data(a[1]) + + # Verify independent wrapper objects + assert data0 is not data1 + + # Verify correct pointers + assert data0.ptr == a[0]._pointer + assert data1.ptr == a[1]._pointer + assert data0.ptr != data1.ptr + + def test_repeated_calls(self): + a = dpt.arange(20) + view = a[5:15] + + # Multiple calls should return independent objects with same ptr + data1 = dpm.create_data(view) + data2 = dpm.create_data(view) + + assert data1 is not data2, "Should create independent wrapper objects" + assert data1.ptr == data2.ptr, "Both should point to same location" + assert data1.ptr == view._pointer + class TestNdarray: def test_ndarray_from_data(self):