Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory allocated with provided MemoryAllocators cannot be pinned multiple times #1755

Closed
4 tasks done
Kloizdena opened this issue Aug 27, 2021 · 1 comment · Fixed by #1756
Closed
4 tasks done

Memory allocated with provided MemoryAllocators cannot be pinned multiple times #1755

Kloizdena opened this issue Aug 27, 2021 · 1 comment · Fixed by #1756
Labels

Comments

@Kloizdena
Copy link

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

When trying to process images, I want to pin the underlying Memory to have access to the pointer and run some SIMD operations. However, when that Memory was allocated with either one of the provided MemoryAllocator classes, I can pin it 1 time only, and on the second try I get IntPtr.Zero as the Pointer.

Steps to Reproduce

The first 2 examples are using ArrayPoolMemoryAllocator and SimpleGcMemoryAllocator and they both fail:

[Test]
public unsafe void MemoryPinningTest_ArrayPoolMemoryAllocator()
{
	var allocator = new SixLabors.ImageSharp.Memory.ArrayPoolMemoryAllocator();
	using var memory = allocator.Allocate<L8>(100); // SixLabors.ImageSharp.Memory.ArrayPoolMemoryAllocator.Buffer<SixLabors.ImageSharp.PixelFormats.L8>
	using (var pin = memory.Memory.Pin())
	{
		Assert.AreNotEqual(IntPtr.Zero, (IntPtr)pin.Pointer);
	}
	using (var pin = memory.Memory.Pin())
	{
		Assert.AreNotEqual(IntPtr.Zero, (IntPtr)pin.Pointer); // this line fails
	}
}
[Test]
public unsafe void MemoryPinningTest_SimpleGcMemoryAllocator()
{
	var allocator = new SixLabors.ImageSharp.Memory.SimpleGcMemoryAllocator();
	using var memory = allocator.Allocate<L8>(100); // SixLabors.ImageSharp.Memory.Internals.BasicArrayBuffer<SixLabors.ImageSharp.PixelFormats.L8>
	using (var pin = memory.Memory.Pin())
	{
		Assert.AreNotEqual(IntPtr.Zero, (IntPtr)pin.Pointer);
	}
	using (var pin = memory.Memory.Pin())
	{
		Assert.AreNotEqual(IntPtr.Zero, (IntPtr)pin.Pointer); // this line fails
	}
}

These other examples are using standard .NET ways to allocate and pin memory and they succeed:

[Test]
public unsafe void MemoryPinningTest_SimpleArray_AsMemory()
{
	var array = new L8[100];
	var memory = array.AsMemory(0, 100);
	using (var pin = memory.Pin())
	{
		Assert.AreNotEqual(IntPtr.Zero, (IntPtr)pin.Pointer);
	}
	using (var pin = memory.Pin())
	{
		Assert.AreNotEqual(IntPtr.Zero, (IntPtr)pin.Pointer);
	}
}
[Test]
public unsafe void MemoryPinningTest_ArrayPool_AsMemory()
{
	var pool = ArrayPool<L8>.Shared;
	var array = pool.Rent(100);
	var memory = array.AsMemory(0, 100);
	using (var pin = memory.Pin())
	{
		Assert.AreNotEqual(IntPtr.Zero, (IntPtr)pin.Pointer);
	}
	using (var pin = memory.Pin())
	{
		Assert.AreNotEqual(IntPtr.Zero, (IntPtr)pin.Pointer);
	}
	pool.Return(array);
}
[Test]
public unsafe void MemoryPinningTest_ArrayPool_PinHandle()
{
	var pool = ArrayPool<L8>.Shared;
	var array = pool.Rent(100);
	var memory = array.AsMemory(0, 100);

	var pinHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
	Assert.AreNotEqual(IntPtr.Zero, (IntPtr)pinHandle.AddrOfPinnedObject());
	pinHandle.Free();

	pinHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
	Assert.AreNotEqual(IntPtr.Zero, (IntPtr)pinHandle.AddrOfPinnedObject());
	pinHandle.Free();

	pool.Return(array);
}
[Test]
public unsafe void MemoryPinningTest_MemoryPool()
{
	var pool = MemoryPool<L8>.Shared;
	using var memory = pool.Rent(100); // System.Buffers.ArrayMemoryPool<SixLabors.ImageSharp.PixelFormats.L8>.ArrayMemoryPoolBuffer
	using (var pin = memory.Memory.Pin())
	{
		Assert.AreNotEqual(IntPtr.Zero, (IntPtr)pin.Pointer);
	}
	using (var pin = memory.Memory.Pin())
	{
		Assert.AreNotEqual(IntPtr.Zero, (IntPtr)pin.Pointer);
	}
}

System Configuration

  • ImageSharp version: SixLabors.ImageSharp 1.0.3
  • Other ImageSharp packages and versions: -
  • Environment (Operating system, version and so on): Microsoft Windows [Version 10.0.19043.1165]
  • .NET Framework version: .NET 5.0.9
  • Additional information: -
@antonfirsov antonfirsov added this to the 2.0.0 milestone Aug 27, 2021
@antonfirsov
Copy link
Member

antonfirsov commented Aug 27, 2021

@Kloizdena thanks a lot for spotting this! I filed a fix which you will be able to consume through MyGet once PR is merged, but note that we will replace ArrayPoolMemoryAllocator in our next official NuGet release and do a bunch of other necessary breaking changes around low-level pixel manipulation. See #1739.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants