Skip to content

Commit

Permalink
Fix #2779 buffer overrun
Browse files Browse the repository at this point in the history
  • Loading branch information
JimBobSquarePants committed Oct 16, 2024
1 parent 4584377 commit 911480d
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 13 deletions.
9 changes: 5 additions & 4 deletions src/ImageSharp/Image.WrapMemory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static Image<TPixel> WrapMemory<TPixel>(
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(metadata, nameof(metadata));
Guard.IsTrue(pixelMemory.Length >= width * height, nameof(pixelMemory), "The length of the input memory is less than the specified image size");
Guard.IsTrue(pixelMemory.Length >= (long)width * height, nameof(pixelMemory), "The length of the input memory is less than the specified image size");

MemoryGroup<TPixel> memorySource = MemoryGroup<TPixel>.Wrap(pixelMemory);
return new Image<TPixel>(configuration, memorySource, width, height, metadata);
Expand Down Expand Up @@ -145,7 +145,7 @@ public static Image<TPixel> WrapMemory<TPixel>(
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(metadata, nameof(metadata));
Guard.IsTrue(pixelMemoryOwner.Memory.Length >= width * height, nameof(pixelMemoryOwner), "The length of the input memory is less than the specified image size");
Guard.IsTrue(pixelMemoryOwner.Memory.Length >= (long)width * height, nameof(pixelMemoryOwner), "The length of the input memory is less than the specified image size");

MemoryGroup<TPixel> memorySource = MemoryGroup<TPixel>.Wrap(pixelMemoryOwner);
return new Image<TPixel>(configuration, memorySource, width, height, metadata);
Expand Down Expand Up @@ -232,7 +232,7 @@ public static Image<TPixel> WrapMemory<TPixel>(

ByteMemoryManager<TPixel> memoryManager = new(byteMemory);

Guard.IsTrue(memoryManager.Memory.Length >= width * height, nameof(byteMemory), "The length of the input memory is less than the specified image size");
Guard.IsTrue(memoryManager.Memory.Length >= (long)width * height, nameof(byteMemory), "The length of the input memory is less than the specified image size");

MemoryGroup<TPixel> memorySource = MemoryGroup<TPixel>.Wrap(memoryManager.Memory);
return new Image<TPixel>(configuration, memorySource, width, height, metadata);
Expand Down Expand Up @@ -422,10 +422,11 @@ public static unsafe Image<TPixel> WrapMemory<TPixel>(
Guard.IsFalse(pointer == null, nameof(pointer), "Pointer must be not null");
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(metadata, nameof(metadata));
Guard.MustBeLessThanOrEqualTo(height * (long)width, int.MaxValue, "Total amount of pixels exceeds int.MaxValue");

UnmanagedMemoryManager<TPixel> memoryManager = new(pointer, width * height);

Guard.MustBeGreaterThanOrEqualTo(bufferSizeInBytes, memoryManager.Memory.Span.Length, nameof(bufferSizeInBytes));
Guard.MustBeGreaterThanOrEqualTo(bufferSizeInBytes / sizeof(TPixel), memoryManager.Memory.Span.Length, nameof(bufferSizeInBytes));

MemoryGroup<TPixel> memorySource = MemoryGroup<TPixel>.Wrap(memoryManager.Memory);
return new Image<TPixel>(configuration, memorySource, width, height, metadata);
Expand Down
30 changes: 21 additions & 9 deletions tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,11 @@ public void WrapSystemDrawingBitmap_FromBytes_WhenObserved()
}
}

[Fact]
public unsafe void WrapMemory_Throws_OnTooLessWrongSize()
[Theory]
[InlineData(20, 5, 5)]
[InlineData(1023, 32, 32)]
[InlineData(65536, 65537, 65536)]
public unsafe void WrapMemory_Throws_OnTooLessWrongSize(int size, int width, int height)
{
var cfg = Configuration.CreateDefaultInstance();
var metaData = new ImageMetadata();
Expand All @@ -306,7 +309,7 @@ public unsafe void WrapMemory_Throws_OnTooLessWrongSize()
{
try
{
using var image = Image.WrapMemory<Rgba32>(cfg, ptr, 24, 5, 5, metaData);
using var image = Image.WrapMemory<Rgba32>(cfg, ptr, size * sizeof(Rgba32), width, height, metaData);
}
catch (Exception e)
{
Expand All @@ -317,24 +320,30 @@ public unsafe void WrapMemory_Throws_OnTooLessWrongSize()
Assert.IsType<ArgumentOutOfRangeException>(thrownException);
}

[Fact]
public unsafe void WrapMemory_FromPointer_CreatedImageIsCorrect()
[Theory]
[InlineData(25, 5, 5)]
[InlineData(26, 5, 5)]
[InlineData(2, 1, 1)]
[InlineData(1024, 32, 32)]
[InlineData(2048, 32, 32)]
public unsafe void WrapMemory_FromPointer_CreatedImageIsCorrect(int size, int width, int height)
{
var cfg = Configuration.CreateDefaultInstance();
var metaData = new ImageMetadata();

var array = new Rgba32[25];
var array = new Rgba32[size];

fixed (void* ptr = array)
{
using (var image = Image.WrapMemory<Rgba32>(cfg, ptr, 25, 5, 5, metaData))
using (var image = Image.WrapMemory<Rgba32>(cfg, ptr, size * sizeof(Rgba32), width, height, metaData))
{
Assert.True(image.DangerousTryGetSinglePixelMemory(out Memory<Rgba32> imageMem));
Span<Rgba32> imageSpan = imageMem.Span;
Span<Rgba32> sourceSpan = array.AsSpan(0, width * height);
ref Rgba32 pixel0 = ref imageSpan[0];
Assert.True(Unsafe.AreSame(ref array[0], ref pixel0));
Assert.True(Unsafe.AreSame(ref sourceSpan[0], ref pixel0));
ref Rgba32 pixel_1 = ref imageSpan[imageSpan.Length - 1];
Assert.True(Unsafe.AreSame(ref array[array.Length - 1], ref pixel_1));
Assert.True(Unsafe.AreSame(ref sourceSpan[sourceSpan.Length - 1], ref pixel_1));

Assert.Equal(cfg, image.Configuration);
Assert.Equal(metaData, image.Metadata);
Expand Down Expand Up @@ -395,6 +404,7 @@ public unsafe void WrapSystemDrawingBitmap_FromPointer()
[InlineData(0, 5, 5)]
[InlineData(20, 5, 5)]
[InlineData(1023, 32, 32)]
[InlineData(65536, 65537, 65536)]
public void WrapMemory_MemoryOfT_InvalidSize(int size, int height, int width)
{
var array = new Rgba32[size];
Expand Down Expand Up @@ -430,6 +440,7 @@ private class TestMemoryOwner<T> : IMemoryOwner<T>
[InlineData(0, 5, 5)]
[InlineData(20, 5, 5)]
[InlineData(1023, 32, 32)]
[InlineData(65536, 65537, 65536)]
public void WrapMemory_IMemoryOwnerOfT_InvalidSize(int size, int height, int width)
{
var array = new Rgba32[size];
Expand Down Expand Up @@ -476,6 +487,7 @@ public void WrapMemory_IMemoryOwnerOfT_ValidSize(int size, int height, int width
[InlineData(0, 5, 5)]
[InlineData(20, 5, 5)]
[InlineData(1023, 32, 32)]
[InlineData(65536, 65537, 65536)]
public void WrapMemory_IMemoryOwnerOfByte_InvalidSize(int size, int height, int width)
{
var array = new byte[size * Unsafe.SizeOf<Rgba32>()];
Expand Down

0 comments on commit 911480d

Please sign in to comment.