From e70e71b16c665e98cb48f464fdc3ab37c614f916 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Wed, 25 Jan 2023 10:57:29 +0100 Subject: [PATCH 1/8] Remove nullable disable from Memory.Allocators #2231 --- .../Memory/Allocators/Internals/Gen2GcCallback.cs | 11 +++++------ .../Allocators/Internals/ManagedBufferBase.cs | 2 +- .../Internals/RefCountedMemoryLifetimeGuard.cs | 3 +-- .../Internals/SharedArrayPoolBuffer{T}.cs | 6 ++---- .../Internals/UniformUnmanagedMemoryPool.cs | 7 +++---- .../Allocators/Internals/UnmanagedMemoryHandle.cs | 11 +++++------ .../UniformUnmanagedMemoryPoolMemoryAllocator.cs | 2 +- src/ImageSharp/Memory/Buffer2DExtensions.cs | 2 +- src/ImageSharp/Memory/Buffer2D{T}.cs | 4 ++-- .../DiscontiguousBuffers/MemoryGroupExtensions.cs | 2 +- .../DiscontiguousBuffers/MemoryGroupSpanCache.cs | 2 +- .../DiscontiguousBuffers/MemoryGroupView{T}.cs | 6 ++++-- .../MemoryGroup{T}.Consumed.cs | 2 +- .../DiscontiguousBuffers/MemoryGroup{T}.Owned.cs | 14 ++++++++------ .../Memory/DiscontiguousBuffers/MemoryGroup{T}.cs | 8 ++++---- 15 files changed, 40 insertions(+), 42 deletions(-) diff --git a/src/ImageSharp/Memory/Allocators/Internals/Gen2GcCallback.cs b/src/ImageSharp/Memory/Allocators/Internals/Gen2GcCallback.cs index 547f67d6a..c0737a114 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/Gen2GcCallback.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/Gen2GcCallback.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable // Port of BCL internal utility: // https://github.com/dotnet/runtime/blob/57bfe474518ab5b7cfe6bf7424a79ce3af9d6657/src/libraries/System.Private.CoreLib/src/System/Gen2GcCallback.cs @@ -15,8 +14,8 @@ namespace SixLabors.ImageSharp.Memory.Internals; /// internal sealed class Gen2GcCallback : CriticalFinalizerObject { - private readonly Func callback0; - private readonly Func callback1; + private readonly Func? callback0; + private readonly Func? callback1; private GCHandle weakTargetObj; private Gen2GcCallback(Func callback) => this.callback0 = callback; @@ -32,7 +31,7 @@ internal sealed class Gen2GcCallback : CriticalFinalizerObject if (this.weakTargetObj.IsAllocated) { // Check to see if the target object is still alive. - object targetObj = this.weakTargetObj.Target; + object? targetObj = this.weakTargetObj.Target; if (targetObj == null) { // The target object is dead, so this callback object is no longer needed. @@ -43,7 +42,7 @@ internal sealed class Gen2GcCallback : CriticalFinalizerObject // Execute the callback method. try { - if (!this.callback1(targetObj)) + if (this.callback1 is not null && !this.callback1(targetObj)) { // If the callback returns false, this callback object is no longer needed. this.weakTargetObj.Free(); @@ -64,7 +63,7 @@ internal sealed class Gen2GcCallback : CriticalFinalizerObject // Execute the callback method. try { - if (!this.callback0()) + if (this.callback0 is not null && !this.callback0()) { // If the callback returns false, this callback object is no longer needed. return; diff --git a/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs b/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs index a18bd3447..be4cb8c8e 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs @@ -43,5 +43,5 @@ internal abstract class ManagedBufferBase : MemoryManager /// Gets the object that should be pinned. /// /// The pinnable . - protected abstract object GetPinnableObject(); + protected abstract object? GetPinnableObject(); } diff --git a/src/ImageSharp/Memory/Allocators/Internals/RefCountedMemoryLifetimeGuard.cs b/src/ImageSharp/Memory/Allocators/Internals/RefCountedMemoryLifetimeGuard.cs index aed5d03e4..4a202a96c 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/RefCountedMemoryLifetimeGuard.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/RefCountedMemoryLifetimeGuard.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using SixLabors.ImageSharp.Diagnostics; @@ -15,7 +14,7 @@ internal abstract class RefCountedMemoryLifetimeGuard : IDisposable private int refCount = 1; private int disposed; private int released; - private string allocationStackTrace; + private string? allocationStackTrace; protected RefCountedMemoryLifetimeGuard() { diff --git a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs index 166992266..1d73b2ddf 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using System.Buffers; using System.Diagnostics; @@ -22,7 +21,7 @@ internal class SharedArrayPoolBuffer : ManagedBufferBase, IRefCounted this.lifetimeGuard = new LifetimeGuard(this.Array); } - public byte[] Array { get; private set; } + public byte[]? Array { get; private set; } protected override void Dispose(bool disposing) { @@ -41,7 +40,7 @@ internal class SharedArrayPoolBuffer : ManagedBufferBase, IRefCounted return MemoryMarshal.Cast(this.Array.AsSpan(0, this.lengthInBytes)); } - protected override object GetPinnableObject() => this.Array; + protected override object? GetPinnableObject() => this.Array; public void AddRef() { @@ -74,7 +73,6 @@ internal class SharedArrayPoolBuffer : ManagedBufferBase, IRefCounted // meaning likely a different bucket than it was rented from, // but this is PROBABLY better than not returning the arrays at all. ArrayPool.Shared.Return(this.array); - this.array = null; } } } diff --git a/src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs b/src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs index 464bc2165..aa8bcd385 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using System.Diagnostics; @@ -13,7 +12,7 @@ internal partial class UniformUnmanagedMemoryPool : System.Runtime.ConstrainedEx { private static int minTrimPeriodMilliseconds = int.MaxValue; private static readonly List> AllPools = new(); - private static Timer trimTimer; + private static Timer? trimTimer; private static readonly Stopwatch Stopwatch = Stopwatch.StartNew(); @@ -97,7 +96,7 @@ internal partial class UniformUnmanagedMemoryPool : System.Runtime.ConstrainedEx /// /// Rent buffers or return 'null' if the pool is full. /// - public UnmanagedMemoryHandle[] Rent(int bufferCount) + public UnmanagedMemoryHandle[]? Rent(int bufferCount) { UnmanagedMemoryHandle[] buffersLocal = this.buffers; @@ -248,7 +247,7 @@ internal partial class UniformUnmanagedMemoryPool : System.Runtime.ConstrainedEx foreach (WeakReference weakPoolRef in AllPools) { - if (weakPoolRef.TryGetTarget(out UniformUnmanagedMemoryPool pool)) + if (weakPoolRef.TryGetTarget(out UniformUnmanagedMemoryPool? pool)) { pool.Trim(); } diff --git a/src/ImageSharp/Memory/Allocators/Internals/UnmanagedMemoryHandle.cs b/src/ImageSharp/Memory/Allocators/Internals/UnmanagedMemoryHandle.cs index a6da445b6..c13fa754e 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/UnmanagedMemoryHandle.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/UnmanagedMemoryHandle.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using System.Runtime.InteropServices; @@ -20,7 +19,7 @@ internal struct UnmanagedMemoryHandle : IEquatable private static long totalOomRetries; // A Monitor to wait/signal when we are low on memory. - private static object lowMemoryMonitor; + private static object? lowMemoryMonitor; public static readonly UnmanagedMemoryHandle NullHandle; @@ -114,9 +113,9 @@ internal struct UnmanagedMemoryHandle : IEquatable if (Volatile.Read(ref lowMemoryMonitor) != null) { // We are low on memory. Signal all threads waiting in AllocateHandle(). - Monitor.Enter(lowMemoryMonitor); - Monitor.PulseAll(lowMemoryMonitor); - Monitor.Exit(lowMemoryMonitor); + Monitor.Enter(lowMemoryMonitor!); + Monitor.PulseAll(lowMemoryMonitor!); + Monitor.Exit(lowMemoryMonitor!); } this.lengthInBytes = 0; @@ -124,7 +123,7 @@ internal struct UnmanagedMemoryHandle : IEquatable public bool Equals(UnmanagedMemoryHandle other) => this.handle.Equals(other.handle); - public override bool Equals(object obj) => obj is UnmanagedMemoryHandle other && this.Equals(other); + public override bool Equals(object? obj) => obj is UnmanagedMemoryHandle other && this.Equals(other); public override int GetHashCode() => this.handle.GetHashCode(); } diff --git a/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs index bf75a716d..2cb4421d5 100644 --- a/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs +++ b/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs @@ -135,7 +135,7 @@ internal sealed class UniformUnmanagedMemoryPoolMemoryAllocator : MemoryAllocato } // Attempt to rent the whole group from the pool, allocate a group of unmanaged buffers if the attempt fails: - if (MemoryGroup.TryAllocate(this.pool, totalLength, bufferAlignment, options, out MemoryGroup poolGroup)) + if (MemoryGroup.TryAllocate(this.pool, totalLength, bufferAlignment, options, out MemoryGroup? poolGroup)) { return poolGroup; } diff --git a/src/ImageSharp/Memory/Buffer2DExtensions.cs b/src/ImageSharp/Memory/Buffer2DExtensions.cs index 2eb05ea93..e7ac64eda 100644 --- a/src/ImageSharp/Memory/Buffer2DExtensions.cs +++ b/src/ImageSharp/Memory/Buffer2DExtensions.cs @@ -22,7 +22,7 @@ public static class Buffer2DExtensions where T : struct { Guard.NotNull(buffer, nameof(buffer)); - return buffer.FastMemoryGroup.View; + return buffer.FastMemoryGroup.View!; } /// diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index 8d6465389..a7957a987 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -43,7 +43,7 @@ public sealed class Buffer2D : IDisposable /// Gets the backing . /// /// The MemoryGroup. - public IMemoryGroup MemoryGroup => this.FastMemoryGroup.View; + public IMemoryGroup? MemoryGroup => this.FastMemoryGroup.View; /// /// Gets the backing without the view abstraction. @@ -138,7 +138,7 @@ public sealed class Buffer2D : IDisposable { DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y)); DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); - return this.FastMemoryGroup.View.GetBoundedMemorySlice(y * (long)this.Width, this.Width); + return this.FastMemoryGroup.View!.GetBoundedMemorySlice(y * (long)this.Width, this.Width); } /// diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs index 4656e6ef9..b4b1ffc6f 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs @@ -106,7 +106,7 @@ internal static class MemoryGroupExtensions } } - internal static void CopyTo(this IMemoryGroup source, IMemoryGroup target) + internal static void CopyTo(this IMemoryGroup? source, IMemoryGroup? target) where T : struct { Guard.NotNull(source, nameof(source)); diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs index 36abfba88..dd3e67c37 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Memory; internal unsafe struct MemoryGroupSpanCache { public SpanCacheMode Mode; - public byte[] SingleArray; + public byte[]? SingleArray; public void* SinglePointer; public void*[] MultiPointer; diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs index 54e347e46..76371e674 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs @@ -1,9 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using System.Buffers; using System.Collections; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Memory; @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Memory; internal class MemoryGroupView : IMemoryGroup where T : struct { - private MemoryGroup owner; + private MemoryGroup? owner; private readonly MemoryOwnerWrapper[] memoryWrappers; public MemoryGroupView(MemoryGroup owner) @@ -63,6 +63,7 @@ internal class MemoryGroupView : IMemoryGroup } } + [MemberNotNullWhen(true, nameof(owner))] public bool IsValid => this.owner != null; public Memory this[int index] @@ -99,6 +100,7 @@ internal class MemoryGroupView : IMemoryGroup this.owner = null; } + [MemberNotNull(nameof(owner))] private void EnsureIsValid() { if (!this.IsValid) diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs index 950e2a019..03a2fb78f 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs @@ -48,6 +48,6 @@ internal abstract partial class MemoryGroup return ((IList>)this.source).GetEnumerator(); } - public override void Dispose() => this.View.Invalidate(); + public override void Dispose() => this.View?.Invalidate(); } } diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs index e5bc91c98..664c137c1 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs @@ -1,8 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using System.Buffers; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory.Internals; @@ -15,8 +15,8 @@ internal abstract partial class MemoryGroup /// public sealed class Owned : MemoryGroup, IEnumerable> { - private IMemoryOwner[] memoryOwners; - private RefCountedMemoryLifetimeGuard groupLifetimeGuard; + private IMemoryOwner[]? memoryOwners; + private RefCountedMemoryLifetimeGuard? groupLifetimeGuard; public Owned(IMemoryOwner[] memoryOwners, int bufferLength, long totalLength, bool swappable) : base(bufferLength, totalLength) @@ -123,7 +123,7 @@ internal abstract partial class MemoryGroup public override void RecreateViewAfterSwap() { - this.View.Invalidate(); + this.View?.Invalidate(); this.View = new MemoryGroupView(this); } @@ -141,7 +141,7 @@ internal abstract partial class MemoryGroup return; } - this.View.Invalidate(); + this.View?.Invalidate(); if (this.groupLifetimeGuard != null) { @@ -149,7 +149,7 @@ internal abstract partial class MemoryGroup } else { - foreach (IMemoryOwner memoryOwner in this.memoryOwners) + foreach (IMemoryOwner memoryOwner in this.memoryOwners!) { memoryOwner.Dispose(); } @@ -161,6 +161,7 @@ internal abstract partial class MemoryGroup } [MethodImpl(InliningOptions.ShortMethod)] + [MemberNotNull(nameof(memoryOwners))] private void EnsureNotDisposed() { if (this.memoryOwners is null) @@ -170,6 +171,7 @@ internal abstract partial class MemoryGroup } [MethodImpl(MethodImplOptions.NoInlining)] + [DoesNotReturn] private static void ThrowObjectDisposedException() => throw new ObjectDisposedException(nameof(MemoryGroup)); // When the MemoryGroup points to multiple buffers via `groupLifetimeGuard`, diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs index 1ef30e354..237cbad7a 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs @@ -1,9 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using System.Buffers; using System.Collections; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory.Internals; @@ -41,7 +41,7 @@ internal abstract partial class MemoryGroup : IMemoryGroup, IDisposable /// public bool IsValid { get; private set; } = true; - public MemoryGroupView View { get; private set; } + public MemoryGroupView? View { get; private set; } /// public abstract Memory this[int index] { get; } @@ -150,7 +150,7 @@ internal abstract partial class MemoryGroup : IMemoryGroup, IDisposable long totalLengthInElements, int bufferAlignmentInElements, AllocationOptions options, - out MemoryGroup memoryGroup) + [NotNullWhen(true)] out MemoryGroup? memoryGroup) { Guard.NotNull(pool, nameof(pool)); Guard.MustBeGreaterThanOrEqualTo(totalLengthInElements, 0, nameof(totalLengthInElements)); @@ -188,7 +188,7 @@ internal abstract partial class MemoryGroup : IMemoryGroup, IDisposable bufferCount++; } - UnmanagedMemoryHandle[] arrays = pool.Rent(bufferCount); + UnmanagedMemoryHandle[]? arrays = pool.Rent(bufferCount); if (arrays == null) { From dfde8d8bf521681b8638980253f0c4ae5b88bb4f Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Wed, 25 Jan 2023 17:11:25 +0100 Subject: [PATCH 2/8] Resolve PR comments --- .../Memory/Allocators/Internals/Gen2GcCallback.cs | 4 ++-- .../Memory/Allocators/Internals/ManagedBufferBase.cs | 2 +- .../Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs | 6 +++++- src/ImageSharp/Memory/Buffer2D{T}.cs | 2 +- .../Memory/DiscontiguousBuffers/MemoryGroup{T}.cs | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Memory/Allocators/Internals/Gen2GcCallback.cs b/src/ImageSharp/Memory/Allocators/Internals/Gen2GcCallback.cs index c0737a114..6f48c5669 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/Gen2GcCallback.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/Gen2GcCallback.cs @@ -42,7 +42,7 @@ internal sealed class Gen2GcCallback : CriticalFinalizerObject // Execute the callback method. try { - if (this.callback1 is not null && !this.callback1(targetObj)) + if (!this.callback1!(targetObj)) { // If the callback returns false, this callback object is no longer needed. this.weakTargetObj.Free(); @@ -63,7 +63,7 @@ internal sealed class Gen2GcCallback : CriticalFinalizerObject // Execute the callback method. try { - if (this.callback0 is not null && !this.callback0()) + if (!this.callback0!()) { // If the callback returns false, this callback object is no longer needed. return; diff --git a/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs b/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs index be4cb8c8e..a18bd3447 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs @@ -43,5 +43,5 @@ internal abstract class ManagedBufferBase : MemoryManager /// Gets the object that should be pinned. /// /// The pinnable . - protected abstract object? GetPinnableObject(); + protected abstract object GetPinnableObject(); } diff --git a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs index 1d73b2ddf..4952c6b5e 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs @@ -40,7 +40,11 @@ internal class SharedArrayPoolBuffer : ManagedBufferBase, IRefCounted return MemoryMarshal.Cast(this.Array.AsSpan(0, this.lengthInBytes)); } - protected override object? GetPinnableObject() => this.Array; + protected override object GetPinnableObject() + { + Guard.NotNull(this.Array); + return this.Array; + } public void AddRef() { diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index a7957a987..8c9093a35 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -43,7 +43,7 @@ public sealed class Buffer2D : IDisposable /// Gets the backing . /// /// The MemoryGroup. - public IMemoryGroup? MemoryGroup => this.FastMemoryGroup.View; + public IMemoryGroup MemoryGroup => this.FastMemoryGroup.View; /// /// Gets the backing without the view abstraction. diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs index 237cbad7a..d63fd2076 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs @@ -41,7 +41,7 @@ internal abstract partial class MemoryGroup : IMemoryGroup, IDisposable /// public bool IsValid { get; private set; } = true; - public MemoryGroupView? View { get; private set; } + public MemoryGroupView View { get; private set; } = null!; /// public abstract Memory this[int index] { get; } From 12cf563c5c54dd6feca7d3acaa0c72d994ae65d1 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Wed, 25 Jan 2023 17:15:42 +0100 Subject: [PATCH 3/8] Use CheckDisposed --- .../Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs index 4952c6b5e..609bb34a5 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs @@ -3,6 +3,7 @@ using System.Buffers; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -42,7 +43,7 @@ internal class SharedArrayPoolBuffer : ManagedBufferBase, IRefCounted protected override object GetPinnableObject() { - Guard.NotNull(this.Array); + this.CheckDisposed(); return this.Array; } @@ -55,6 +56,7 @@ internal class SharedArrayPoolBuffer : ManagedBufferBase, IRefCounted public void ReleaseRef() => this.lifetimeGuard.ReleaseRef(); [Conditional("DEBUG")] + [MemberNotNull(nameof(Array))] private void CheckDisposed() { if (this.Array == null) From 4efd49295a227ac57509db045774c07ee4283825 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Wed, 25 Jan 2023 17:56:21 +0100 Subject: [PATCH 4/8] Resolve PR issues --- .../Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs | 5 +++-- .../Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs index 609bb34a5..f9434ee94 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs @@ -67,7 +67,7 @@ internal class SharedArrayPoolBuffer : ManagedBufferBase, IRefCounted private sealed class LifetimeGuard : RefCountedMemoryLifetimeGuard { - private byte[] array; + private byte[]? array; public LifetimeGuard(byte[] array) => this.array = array; @@ -78,7 +78,8 @@ internal class SharedArrayPoolBuffer : ManagedBufferBase, IRefCounted // This is not ideal, but subsequent leaks will end up returning arrays to per-cpu buckets, // meaning likely a different bucket than it was rented from, // but this is PROBABLY better than not returning the arrays at all. - ArrayPool.Shared.Return(this.array); + ArrayPool.Shared.Return(this.array!); + this.array = null; } } } diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs index 03a2fb78f..950e2a019 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs @@ -48,6 +48,6 @@ internal abstract partial class MemoryGroup return ((IList>)this.source).GetEnumerator(); } - public override void Dispose() => this.View?.Invalidate(); + public override void Dispose() => this.View.Invalidate(); } } From 12421030c2846ceee2e886f397b9c84d7bc9cb1a Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Wed, 25 Jan 2023 19:42:05 +0100 Subject: [PATCH 5/8] Update src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs Co-authored-by: Anton Firszov --- .../Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs index 664c137c1..eab90ee5a 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs @@ -123,7 +123,7 @@ internal abstract partial class MemoryGroup public override void RecreateViewAfterSwap() { - this.View?.Invalidate(); + this.View.Invalidate(); this.View = new MemoryGroupView(this); } From 8f18e3596089a237d7a9bf59cbb9997b4219af5a Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Wed, 25 Jan 2023 19:42:13 +0100 Subject: [PATCH 6/8] Update src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs Co-authored-by: Anton Firszov --- .../Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs index eab90ee5a..9da0139e6 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs @@ -141,7 +141,7 @@ internal abstract partial class MemoryGroup return; } - this.View?.Invalidate(); + this.View.Invalidate(); if (this.groupLifetimeGuard != null) { From 6e70477cf2e477c1fbc981a1a31e68c6ff9399e2 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Wed, 25 Jan 2023 19:42:21 +0100 Subject: [PATCH 7/8] Update src/ImageSharp/Memory/Buffer2D{T}.cs Co-authored-by: Anton Firszov --- src/ImageSharp/Memory/Buffer2D{T}.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index 8c9093a35..8d6465389 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -138,7 +138,7 @@ public sealed class Buffer2D : IDisposable { DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y)); DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); - return this.FastMemoryGroup.View!.GetBoundedMemorySlice(y * (long)this.Width, this.Width); + return this.FastMemoryGroup.View.GetBoundedMemorySlice(y * (long)this.Width, this.Width); } /// From 9c3d68f1f55f87d44822f91a98e053847218e674 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Wed, 25 Jan 2023 19:42:28 +0100 Subject: [PATCH 8/8] Update src/ImageSharp/Memory/Buffer2DExtensions.cs Co-authored-by: Anton Firszov --- src/ImageSharp/Memory/Buffer2DExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Memory/Buffer2DExtensions.cs b/src/ImageSharp/Memory/Buffer2DExtensions.cs index e7ac64eda..2eb05ea93 100644 --- a/src/ImageSharp/Memory/Buffer2DExtensions.cs +++ b/src/ImageSharp/Memory/Buffer2DExtensions.cs @@ -22,7 +22,7 @@ public static class Buffer2DExtensions where T : struct { Guard.NotNull(buffer, nameof(buffer)); - return buffer.FastMemoryGroup.View!; + return buffer.FastMemoryGroup.View; } ///