Skip to content

Commit 63d4b20

Browse files
Fix args and add tests
1 parent 7dd3c43 commit 63d4b20

File tree

21 files changed

+131
-71
lines changed

21 files changed

+131
-71
lines changed

src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/ComponentProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public ComponentProcessor(MemoryAllocator memoryAllocator, JpegFrame frame, Size
1616
this.Component = component;
1717

1818
this.BlockAreaSize = component.SubSamplingDivisors * blockSize;
19-
this.ColorBuffer = memoryAllocator.Allocate2DOveraligned<float>(
19+
this.ColorBuffer = memoryAllocator.Allocate2DOverAligned<float>(
2020
postProcessorBufferSize.Width,
2121
postProcessorBufferSize.Height,
2222
this.BlockAreaSize.Height);

src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public ComponentProcessor(MemoryAllocator memoryAllocator, Component component,
2828
this.blockAreaSize = component.SubSamplingDivisors * 8;
2929

3030
// alignment of 8 so each block stride can be sampled from a single 'ref pointer'
31-
this.ColorBuffer = memoryAllocator.Allocate2DOveraligned<float>(
31+
this.ColorBuffer = memoryAllocator.Allocate2DOverAligned<float>(
3232
postProcessorBufferSize.Width,
3333
postProcessorBufferSize.Height,
3434
8,

src/ImageSharp/Formats/Png/PngDecoderCore.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,6 +1968,9 @@ private IMemoryOwner<byte> ReadChunkData(int length)
19681968
}
19691969

19701970
// We rent the buffer here to return it afterwards in Decode()
1971+
// We don't want to throw a degenerated memory exception here as we want to allow partial decoding
1972+
// so limit the length.
1973+
length = (int)Math.Min(length, this.currentStream.Length - this.currentStream.Position);
19711974
IMemoryOwner<byte> buffer = this.configuration.MemoryAllocator.Allocate<byte>(length, AllocationOptions.Clean);
19721975

19731976
this.currentStream.Read(buffer.GetSpan(), 0, length);

src/ImageSharp/Formats/Tga/TgaDecoderCore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
8484
throw new UnknownImageFormatException("Width or height cannot be 0");
8585
}
8686

87-
Image<TPixel> image = Image.CreateUninitialized<TPixel>(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata);
87+
Image<TPixel> image = new(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata);
8888
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
8989

9090
if (this.fileHeader.ColorMapType == 1)

src/ImageSharp/Memory/Allocators/MemoryAllocator.cs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the Six Labors Split License.
33

44
using System.Buffers;
5-
using System.Diagnostics.CodeAnalysis;
65
using System.Runtime.CompilerServices;
76

87
namespace SixLabors.ImageSharp.Memory;
@@ -24,9 +23,7 @@ public abstract class MemoryAllocator
2423
/// </summary>
2524
public static MemoryAllocator Default { get; } = Create();
2625

27-
internal long MemoryGroupAllocationLimitBytes { get; private set; } = Environment.Is64BitProcess ?
28-
4L * OneGigabyte :
29-
OneGigabyte;
26+
internal long MemoryGroupAllocationLimitBytes { get; private set; } = Environment.Is64BitProcess ? 4L * OneGigabyte : OneGigabyte;
3027

3128
internal int SingleBufferAllocationLimitBytes { get; private set; } = OneGigabyte;
3229

@@ -82,6 +79,7 @@ public virtual void ReleaseRetainedResources()
8279
/// <summary>
8380
/// Allocates a <see cref="MemoryGroup{T}"/>.
8481
/// </summary>
82+
/// <typeparam name="T">The type of element to allocate.</typeparam>
8583
/// <param name="totalLength">The total length of the buffer.</param>
8684
/// <param name="bufferAlignment">The expected alignment (eg. to make sure image rows fit into single buffers).</param>
8785
/// <param name="options">The <see cref="AllocationOptions"/>.</param>
@@ -93,22 +91,19 @@ internal MemoryGroup<T> AllocateGroup<T>(
9391
AllocationOptions options = AllocationOptions.None)
9492
where T : struct
9593
{
96-
long totalLengthInBytes = totalLength * Unsafe.SizeOf<T>();
97-
if (totalLengthInBytes < 0)
94+
if (totalLength < 0)
9895
{
99-
ThrowNotRepresentable();
96+
InvalidMemoryOperationException.ThrowNegativeAllocationException(totalLength);
10097
}
10198

102-
if (totalLengthInBytes > this.MemoryGroupAllocationLimitBytes)
99+
ulong totalLengthInBytes = (ulong)totalLength * (ulong)Unsafe.SizeOf<T>();
100+
if (totalLengthInBytes > (ulong)this.MemoryGroupAllocationLimitBytes)
103101
{
104102
InvalidMemoryOperationException.ThrowAllocationOverLimitException(totalLengthInBytes, this.MemoryGroupAllocationLimitBytes);
105103
}
106104

107-
return this.AllocateGroupCore<T>(totalLengthInBytes, totalLength, bufferAlignment, options);
108-
109-
[DoesNotReturn]
110-
static void ThrowNotRepresentable() =>
111-
throw new InvalidMemoryOperationException("Attempted to allocate a MemoryGroup of a size that is not representable.");
105+
// Cast to long is safe because we already checked that the total length is within the limit.
106+
return this.AllocateGroupCore<T>(totalLength, (long)totalLengthInBytes, bufferAlignment, options);
112107
}
113108

114109
internal virtual MemoryGroup<T> AllocateGroupCore<T>(long totalLengthInElements, long totalLengthInBytes, int bufferAlignment, AllocationOptions options)

src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public struct MemoryAllocatorOptions
1717
/// </summary>
1818
public int? MaximumPoolSizeMegabytes
1919
{
20-
get => this.maximumPoolSizeMegabytes;
20+
readonly get => this.maximumPoolSizeMegabytes;
2121
set
2222
{
2323
if (value.HasValue)
@@ -35,7 +35,7 @@ public int? MaximumPoolSizeMegabytes
3535
/// </summary>
3636
public int? AllocationLimitMegabytes
3737
{
38-
get => this.allocationLimitMegabytes;
38+
readonly get => this.allocationLimitMegabytes;
3939
set
4040
{
4141
if (value.HasValue)

src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ public sealed class SimpleGcMemoryAllocator : MemoryAllocator
1818
/// <inheritdoc />
1919
public override IMemoryOwner<T> Allocate<T>(int length, AllocationOptions options = AllocationOptions.None)
2020
{
21-
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
22-
23-
int lengthInBytes = length * Unsafe.SizeOf<T>();
21+
if (length < 0)
22+
{
23+
InvalidMemoryOperationException.ThrowNegativeAllocationException(length);
24+
}
2425

25-
if (lengthInBytes > this.SingleBufferAllocationLimitBytes)
26+
ulong lengthInBytes = (ulong)length * (ulong)Unsafe.SizeOf<T>();
27+
if (lengthInBytes > (ulong)this.SingleBufferAllocationLimitBytes)
2628
{
2729
InvalidMemoryOperationException.ThrowAllocationOverLimitException(lengthInBytes, this.SingleBufferAllocationLimitBytes);
2830
}

src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the Six Labors Split License.
33

44
using System.Buffers;
5-
using System.Diagnostics.CodeAnalysis;
65
using System.Runtime.CompilerServices;
76
using SixLabors.ImageSharp.Memory.Internals;
87

@@ -84,15 +83,18 @@ public override IMemoryOwner<T> Allocate<T>(
8483
int length,
8584
AllocationOptions options = AllocationOptions.None)
8685
{
87-
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
88-
int lengthInBytes = length * Unsafe.SizeOf<T>();
86+
if (length < 0)
87+
{
88+
InvalidMemoryOperationException.ThrowNegativeAllocationException(length);
89+
}
8990

90-
if (lengthInBytes > this.SingleBufferAllocationLimitBytes)
91+
ulong lengthInBytes = (ulong)length * (ulong)Unsafe.SizeOf<T>();
92+
if (lengthInBytes > (ulong)this.SingleBufferAllocationLimitBytes)
9193
{
9294
InvalidMemoryOperationException.ThrowAllocationOverLimitException(lengthInBytes, this.SingleBufferAllocationLimitBytes);
9395
}
9496

95-
if (lengthInBytes <= this.sharedArrayPoolThresholdInBytes)
97+
if (lengthInBytes <= (ulong)this.sharedArrayPoolThresholdInBytes)
9698
{
9799
var buffer = new SharedArrayPoolBuffer<T>(length);
98100
if (options.Has(AllocationOptions.Clean))
@@ -103,7 +105,7 @@ public override IMemoryOwner<T> Allocate<T>(
103105
return buffer;
104106
}
105107

106-
if (lengthInBytes <= this.poolBufferSizeInBytes)
108+
if (lengthInBytes <= (ulong)this.poolBufferSizeInBytes)
107109
{
108110
UnmanagedMemoryHandle mem = this.pool.Rent();
109111
if (mem.IsValid)

src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,16 @@ public static MemoryGroup<T> Allocate(
8383
{
8484
int bufferCapacityInBytes = allocator.GetBufferCapacityInBytes();
8585
Guard.NotNull(allocator, nameof(allocator));
86-
Guard.MustBeGreaterThanOrEqualTo(totalLengthInElements, 0, nameof(totalLengthInElements));
87-
Guard.MustBeGreaterThanOrEqualTo(bufferAlignmentInElements, 0, nameof(bufferAlignmentInElements));
8886

89-
int blockCapacityInElements = bufferCapacityInBytes / ElementSize;
87+
if (totalLengthInElements < 0)
88+
{
89+
InvalidMemoryOperationException.ThrowNegativeAllocationException(totalLengthInElements);
90+
}
9091

91-
if (bufferAlignmentInElements > blockCapacityInElements)
92+
int blockCapacityInElements = bufferCapacityInBytes / ElementSize;
93+
if (bufferAlignmentInElements < 0 || bufferAlignmentInElements > blockCapacityInElements)
9294
{
93-
throw new InvalidMemoryOperationException(
94-
$"The buffer capacity of the provided MemoryAllocator is insufficient for the requested buffer alignment: {bufferAlignmentInElements}.");
95+
InvalidMemoryOperationException.ThrowInvalidAlignmentException(bufferAlignmentInElements);
9596
}
9697

9798
if (totalLengthInElements == 0)

src/ImageSharp/Memory/InvalidMemoryOperationException.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ public InvalidMemoryOperationException()
2828
}
2929

3030
[DoesNotReturn]
31-
internal static void ThrowAllocationOverLimitException(long length, long limit) =>
31+
internal static void ThrowNegativeAllocationException(long length) =>
32+
throw new InvalidMemoryOperationException($"Attempted to allocate a buffer of negative length={length}.");
33+
34+
[DoesNotReturn]
35+
internal static void ThrowInvalidAlignmentException(long alignment) =>
36+
throw new InvalidMemoryOperationException(
37+
$"The buffer capacity of the provided MemoryAllocator is insufficient for the requested buffer alignment: {alignment}.");
38+
39+
[DoesNotReturn]
40+
internal static void ThrowAllocationOverLimitException(ulong length, long limit) =>
3241
throw new InvalidMemoryOperationException($"Attempted to allocate a buffer of length={length} that exceeded the limit {limit}.");
3342
}

0 commit comments

Comments
 (0)