diff --git a/src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.Buffer{T}.cs b/src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.Buffer{T}.cs index 56209d343e..bc4dc5c820 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.Buffer{T}.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.Buffer{T}.cs @@ -26,6 +26,7 @@ namespace SixLabors.ImageSharp.Memory.Internals return; } + this.VerifyMemorySentinel(); this.pool.Return(this.BufferHandle); this.pool = null; this.BufferHandle = null; diff --git a/src/ImageSharp/Memory/Allocators/Internals/UnmanagedBuffer{T}.cs b/src/ImageSharp/Memory/Allocators/Internals/UnmanagedBuffer{T}.cs index c343e44a8d..6c76a18d8a 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/UnmanagedBuffer{T}.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/UnmanagedBuffer{T}.cs @@ -3,6 +3,7 @@ using System; using System.Buffers; +using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -61,10 +62,15 @@ namespace SixLabors.ImageSharp.Memory.Internals return; } + this.VerifyMemorySentinel(); + if (disposing) { this.BufferHandle.Dispose(); } } + + [Conditional("MEMORY_SENTINEL")] + protected void VerifyMemorySentinel() => this.BufferHandle.VerifyMemorySentinel(this.lengthInElements * Unsafe.SizeOf()); } } diff --git a/src/ImageSharp/Memory/Allocators/Internals/UnmanagedMemoryHandle.cs b/src/ImageSharp/Memory/Allocators/Internals/UnmanagedMemoryHandle.cs index 12ea933bb9..2cb6510383 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/UnmanagedMemoryHandle.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/UnmanagedMemoryHandle.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; using Microsoft.Win32.SafeHandles; @@ -24,6 +25,12 @@ namespace SixLabors.ImageSharp.Memory.Internals // A Monitor to wait/signal when we are low on memory. private static object lowMemoryMonitor; +#if MEMORY_SENTINEL + private const int MemorySentinelPadding = 16; +#else + private const int MemorySentinelPadding = 0; +#endif + private UnmanagedMemoryHandle(IntPtr handle, int lengthInBytes) : base(handle, true) { @@ -77,10 +84,31 @@ namespace SixLabors.ImageSharp.Memory.Internals internal static UnmanagedMemoryHandle Allocate(int lengthInBytes) { - IntPtr handle = AllocateHandle(lengthInBytes); + IntPtr handle = AllocateHandle(lengthInBytes + MemorySentinelPadding); +#if MEMORY_SENTINEL + unsafe + { + new Span((void*)handle, lengthInBytes + MemorySentinelPadding).Fill(42); + } +#endif return new UnmanagedMemoryHandle(handle, lengthInBytes); } + [Conditional("MEMORY_SENTINEL")] + internal unsafe void VerifyMemorySentinel(int actualLengthInBytes) + { + Span remainder = + new Span((void*)this.handle, this.lengthInBytes + MemorySentinelPadding) + .Slice(actualLengthInBytes); + for (int i = 0; i < remainder.Length; i++) + { + if (remainder[i] != 42) + { + throw new InvalidMemoryOperationException("Memory corruption detected!"); + } + } + } + private static IntPtr AllocateHandle(int lengthInBytes) { int counter = 0;