Visitar URL original
Introduce additional pre-checks in PyBuffer_GetPointer to prevent memory corruption by filmor · Pull Request #2745 · pythonnet/pythonnet · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Add more checks and tests
  • Loading branch information
filmor committed Sep 29, 2026
commit ea384d9c5f1d2f370363f299d6a1328de08befcb
32 changes: 28 additions & 4 deletions src/embed_tests/TestPyBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;

using NUnit.Framework;

using Python.Runtime;
using Python.Runtime.Codecs;

namespace Python.EmbeddingTest {
namespace Python.EmbeddingTest
{
class TestPyBuffer
{
[OneTimeSetUp]
Expand Down Expand Up @@ -70,16 +73,37 @@ public void GetPointer()

using PyBuffer buf = ndArray.GetBuffer(PyBUF.STRIDES);

// this throws System.ExecutionEngineException
var ptr = buf.GetPointer([0, 0, 0]);

Assert.That(ptr, Is.Not.EqualTo(IntPtr.Zero));

var ptrEnd = buf.GetPointer([9, 9, 9]);
Assert.That(ptrEnd, Is.Not.EqualTo(IntPtr.Zero));

Assert.Throws<ArgumentNullException>(() => buf.GetPointer(null!));

Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([0, 0]));
Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([0, 0, 0, 0]));

Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([-1, 0, 0]));
Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([0, -1, 0]));
Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([0, 0, -1]));

Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([10, 0, 0]));
Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([0, 10, 0]));
Assert.Throws<ArgumentOutOfRangeException>(() => buf.GetPointer([0, 0, 10]));

using PyBuffer buf2 = ndArray.GetBuffer(PyBUF.ND);

Assert.Throws<InvalidOperationException>(
() => buf2.GetPointer([0, 0, 0])
);
}

[Test]
public void ArrayHasBuffer()
{
var array = new[,] {{1, 2}, {3,4}};
var array = new[,] { { 1, 2 }, { 3, 4 } };
var memoryView = PythonEngine.Eval("memoryview");
var mem = memoryView.Invoke(array.ToPython());
Assert.That(mem[(0, 0).ToPython()].As<int>(), Is.EqualTo(1));
Expand Down Expand Up @@ -128,7 +152,7 @@ public void Finalization()
[Test]
public void MultidimensionalNumPyArray()
{
var ndarray = np.arange(24).reshape(1,2,3,4).T;
var ndarray = np.arange(24).reshape(1, 2, 3, 4).T;
PyObject ndim = ndarray.ndim;
PyObject shape = ndarray.shape;
PyObject strides = ndarray.strides;
Expand Down
29 changes: 28 additions & 1 deletion src/runtime/PythonTypes/PyBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,37 @@ public bool IsContiguous(BufferOrderStyle order)
/// </summary>
public IntPtr GetPointer(long[] indices)
{
if (indices is null) throw new ArgumentNullException(nameof(indices));
if (indices is null)
throw new ArgumentNullException(nameof(indices));

if (Strides is null)
throw new InvalidOperationException($"{nameof(GetPointer)} requires {nameof(Strides)} to be filled");

if (indices.Length != Dimensions)
throw new ArgumentOutOfRangeException($"{nameof(indices)} must be exactly {Dimensions} long");

if (Dimensions == 0 && Shape is null)
throw new InvalidOperationException($"{nameof(GetPointer)} requires {nameof(Shape)} to be filled for dimensional buffers");

ThrowIfDisposed();

if (Runtime.PyVersion < new Version(3, 7))
throw new NotSupportedException("GetPointer requires at least Python 3.7");

var indicesArr = new nint[Dimensions];

for (var i = 0; i < Dimensions; i++)
{
indicesArr[i] = checked((nint)indices[i]);

if (indicesArr[i] < 0 || indicesArr[i] >= Shape![i])
{
throw new ArgumentOutOfRangeException(
$"Index {i} has a value of {indicesArr[i]} not in [0, {Shape![i]})"
);
}
}

return Runtime.PyBuffer_GetPointer(ref _view, indices.Select(x => checked((nint)x)).ToArray());
}

Expand Down
Loading