Browse Source

[SL.Core] Throw better exceptions from MemoryAllocators

pull/1087/head
Anton Firszov 7 years ago
parent
commit
4671658b7b
  1. 11
      src/SixLabors.Core/Memory/ArrayPoolMemoryAllocator.cs
  2. 7
      src/SixLabors.Core/Memory/SimpleGcMemoryAllocator.cs
  3. 24
      tests/SixLabors.Core.Tests/Memory/ArrayPoolMemoryAllocatorTests.cs
  4. 45
      tests/SixLabors.Core.Tests/Memory/SimpleGcMemoryAllocatorTests.cs
  5. 16
      tests/SixLabors.Core.Tests/Memory/SimpleGcMemoryManagerTests.cs

11
src/SixLabors.Core/Memory/ArrayPoolMemoryAllocator.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
@ -91,8 +92,15 @@ namespace SixLabors.Memory
/// <inheritdoc />
public override IMemoryOwner<T> Allocate<T>(int length, AllocationOptions options = AllocationOptions.None)
{
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
int itemSizeBytes = Unsafe.SizeOf<T>();
int bufferSizeInBytes = length * itemSizeBytes;
if (bufferSizeInBytes < 0)
{
throw new ArgumentOutOfRangeException(
nameof(length),
$"{nameof(ArrayPoolMemoryAllocator)} can not allocate {length} elements of {typeof(T).Name}.");
}
ArrayPool<byte> pool = this.GetArrayPool(bufferSizeInBytes);
byte[] byteArray = pool.Rent(bufferSizeInBytes);
@ -109,6 +117,9 @@ namespace SixLabors.Memory
/// <inheritdoc />
public override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None)
{
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
Guard.MustBeLessThan(length, int.MaxValue, nameof(length));
ArrayPool<byte> pool = this.GetArrayPool(length);
byte[] byteArray = pool.Rent(length);

7
src/SixLabors.Core/Memory/SimpleGcMemoryAllocator.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.Memory.Internals;
@ -14,12 +15,18 @@ namespace SixLabors.Memory
/// <inheritdoc />
public override IMemoryOwner<T> Allocate<T>(int length, AllocationOptions options = AllocationOptions.None)
{
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
Guard.MustBeLessThan(length, int.MaxValue, nameof(length));
return new BasicArrayBuffer<T>(new T[length]);
}
/// <inheritdoc />
public override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None)
{
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
Guard.MustBeLessThan(length, int.MaxValue, nameof(length));
return new BasicByteBuffer(new byte[length]);
}
}

24
tests/SixLabors.Core.Tests/Memory/ArrayPoolMemoryManagerTests.cs → tests/SixLabors.Core.Tests/Memory/ArrayPoolMemoryAllocatorTests.cs

@ -12,7 +12,7 @@ using Xunit;
namespace SixLabors.Memory.Tests
{
public class ArrayPoolMemoryManagerTests
public class ArrayPoolMemoryAllocatorTests
{
private const int MaxPooledBufferSizeInBytes = 2048;
@ -231,9 +231,29 @@ namespace SixLabors.Memory.Tests
private uint dummy;
}
[StructLayout(LayoutKind.Explicit, Size = MaxPooledBufferSizeInBytes / 5)]
private const int SizeOfLargeStruct = MaxPooledBufferSizeInBytes / 5;
[StructLayout(LayoutKind.Explicit, Size = SizeOfLargeStruct)]
private struct LargeStruct
{
}
[Theory]
[InlineData(-1)]
[InlineData((int.MaxValue / SizeOfLargeStruct) + 1)]
public void AllocateIncorrectAmount_ThrowsCorrect_ArgumentOutOfRangeException(int length)
{
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => this.MemoryAllocator.Allocate<LargeStruct>(length));
Assert.Equal("length", ex.ParamName);
}
[Theory]
[InlineData(-1)]
[InlineData(int.MaxValue)]
public void AllocateManagedByteBuffer_IncorrectAmount_ThrowsCorrect_ArgumentOutOfRangeException(int length)
{
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => this.MemoryAllocator.AllocateManagedByteBuffer(length));
Assert.Equal("length", ex.ParamName);
}
}
}

45
tests/SixLabors.Core.Tests/Memory/SimpleGcMemoryAllocatorTests.cs

@ -0,0 +1,45 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.InteropServices;
using Xunit;
namespace SixLabors.Memory.Tests
{
public class SimpleGcMemoryAllocatorTests
{
public class BufferTests : BufferTestSuite
{
public BufferTests()
: base(new SimpleGcMemoryAllocator())
{
}
}
protected SimpleGcMemoryAllocator MemoryAllocator { get; } = new SimpleGcMemoryAllocator();
[Theory]
[InlineData(-1)]
[InlineData(int.MaxValue)]
public void Allocate_IncorrectAmount_ThrowsCorrect_ArgumentOutOfRangeException(int length)
{
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => this.MemoryAllocator.Allocate<BigStruct>( length));
Assert.Equal("length", ex.ParamName);
}
[Theory]
[InlineData(-1)]
[InlineData(int.MaxValue)]
public void AllocateManagedByteBuffer_IncorrectAmount_ThrowsCorrect_ArgumentOutOfRangeException(int length)
{
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => this.MemoryAllocator.AllocateManagedByteBuffer(length));
Assert.Equal("length", ex.ParamName);
}
[StructLayout(LayoutKind.Explicit, Size = 512)]
private struct BigStruct
{
}
}
}

16
tests/SixLabors.Core.Tests/Memory/SimpleGcMemoryManagerTests.cs

@ -1,16 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.Memory.Tests
{
public class SimpleGcMemoryManagerTests
{
public class BufferTests : BufferTestSuite
{
public BufferTests()
: base(new SimpleGcMemoryAllocator())
{
}
}
}
}
Loading…
Cancel
Save