FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Introduce additional pre-checks in PyBuffer_GetPointer to prevent mem… · pythonnet/pythonnet@22c5d77 · GitHub

Repository navigation

Commit 22c5d77

Browse files
authored
Introduce additional pre-checks in PyBuffer_GetPointer to prevent memory corruption (#2745)
* Add test for `PyBuffer.GetPointer` * Add more checks and tests
1 parent 33b9fd2 commit 22c5d77

2 files changed

Lines changed: 71 additions & 5 deletions

File tree

‎src/embed_tests/TestPyBuffer.cs‎

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
using System.Runtime.CompilerServices;
33
using System.Text;
44
using System.Threading;
5+
56
using NUnit.Framework;
7+
68
using Python.Runtime;
79
using Python.Runtime.Codecs;
810

9-
namespace Python.EmbeddingTest {
11+
namespace Python.EmbeddingTest
12+
{
1013
class TestPyBuffer
1114
{
1215
[OneTimeSetUp]
@@ -58,13 +61,49 @@ public void TestBufferRead()
5861
}
5962

6063
string result = new UTF8Encoding().GetString(managedArray);
61-
Assert.That(result == " " + bufferTestString.Substring(1), Is.True);
64+
Assert.That(result, Is.EqualTo($" {bufferTestString.Substring(1)}"));
65+
}
66+
67+
[Test]
68+
public void GetPointer()
69+
{
70+
// create 3D NumPy array
71+
int[] shape = [10, 10, 10];
72+
using PyObject ndArray = np.zeros(shape);
73+
74+
using PyBuffer buf = ndArray.GetBuffer(PyBUF.STRIDES);
75+
76+
var ptr = buf.GetPointer([0, 0, 0]);
77+
78+
Assert.That(ptr, Is.Not.EqualTo(IntPtr.Zero));
79+
80+
var ptrEnd = buf.GetPointer([9, 9, 9]);
81+
Assert.That(ptrEnd, Is.Not.EqualTo(IntPtr.Zero));
82+
83+
Assert.Throws<ArgumentNullException>(() => buf.GetPointer(null!));
84+
85+
Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([0, 0]));
86+
Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([0, 0, 0, 0]));
87+
88+
Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([-1, 0, 0]));
89+
Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([0, -1, 0]));
90+
Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([0, 0, -1]));
91+
92+
Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([10, 0, 0]));
93+
Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([0, 10, 0]));
94+
Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([0, 0, 10]));
95+
96+
using PyBuffer buf2 = ndArray.GetBuffer(PyBUF.ND);
97+
98+
Assert.Throws<InvalidOperationException>(
99+
() => buf2.GetPointer([0, 0, 0])
100+
);
62101
}
63102

64103
[Test]
65104
public void ArrayHasBuffer()
66105
{
67-
var array = new[,] {{1, 2}, {3,4}};
106+
var array = new[,] { { 1, 2 }, { 3, 4 } };
68107
var memoryView = PythonEngine.Eval("memoryview");
69108
var mem = memoryView.Invoke(array.ToPython());
70109
Assert.That(mem[(0, 0).ToPython()].As<int>(), Is.EqualTo(1));
@@ -113,7 +152,7 @@ public void Finalization()
113152
[Test]
114153
public void MultidimensionalNumPyArray()
115154
{
116-
var ndarray = np.arange(24).reshape(1,2,3,4).T;
155+
var ndarray = np.arange(24).reshape(1, 2, 3, 4).T;
117156
PyObject ndim = ndarray.ndim;
118157
PyObject shape = ndarray.shape;
119158
PyObject strides = ndarray.strides;

‎src/runtime/PythonTypes/PyBuffer.cs‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,37 @@ public bool IsContiguous(BufferOrderStyle order)
110110
/// </summary>
111111
public IntPtr GetPointer(long[] indices)
112112
{
113-
if (indices is null) throw new ArgumentNullException(nameof(indices));
113+
if (indices is null)
114+
throw new ArgumentNullException(nameof(indices));
115+
116+
if (Strides is null)
117+
throw new InvalidOperationException($"{nameof(GetPointer)} requires {nameof(Strides)} to be filled");
118+
119+
if (indices.Length != Dimensions)
120+
throw new ArgumentOutOfRangeException($"{nameof(indices)} must be exactly {Dimensions} long");
121+
122+
if (Dimensions == 0 && Shape is null)
123+
throw new InvalidOperationException($"{nameof(GetPointer)} requires {nameof(Shape)} to be filled for dimensional buffers");
124+
114125
ThrowIfDisposed();
126+
115127
if (Runtime.PyVersion < new Version(3, 7))
116128
throw new NotSupportedException("GetPointer requires at least Python 3.7");
129+
130+
var indicesArr = new nint[Dimensions];
131+
132+
for (var i = 0; i < Dimensions; i++)
133+
{
134+
indicesArr[i] = checked((nint)indices[i]);
135+
136+
if (indicesArr[i] < 0 || indicesArr[i] >= Shape![i])
137+
{
138+
throw new ArgumentOutOfRangeException(
139+
$"Index {i} has a value of {indicesArr[i]} not in [0, {Shape![i]})"
140+
);
141+
}
142+
}
143+
117144
return Runtime.PyBuffer_GetPointer(ref _view, indices.Select(x => checked((nint)x)).ToArray());
118145
}
119146

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL