Skip to content

Commit

Permalink
Add NativeMemory.ZeroMemory API (dotnet#69500)
Browse files Browse the repository at this point in the history
* Add NativeMemory.ZeroMemory API

* Replace Random.NextBytes with Span<byte>.Fill

* Add ZeroMemory unit tests for zeroed region within buffer

* Add remarks for ptr and byteCount parameters

* Add test for ZeroMemory(null, 0) not throwing

* Add unit tests for zeroing memory with a size of 0

* Move test cases with 0 byte count to separate method

Co-authored-by: Stephen Toub <stoub@microsoft.com>
  • Loading branch information
Sergio0694 and stephentoub committed May 20, 2022
1 parent 334989f commit 6a00977
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ public static unsafe partial class NativeMemory
return AllocZeroed(byteCount, elementSize: 1);
}

/// <summary>Clears a block of memory.</summary>
/// <param name="ptr">A pointer to the block of memory that should be cleared.</param>
/// <param name="byteCount">The size, in bytes, of the block to clear.</param>
/// <remarks>
/// <para>If this method is called with <paramref name="ptr" /> being <see langword="null"/> and <paramref name="byteCount" /> being <c>0</c>, it will be equivalent to a no-op.</para>
/// <para>The behavior when <paramref name="ptr" /> is <see langword="null"/> and <paramref name="byteCount" /> is greater than <c>0</c> is undefined.</para>
/// </remarks>
[CLSCompliant(false)]
public static unsafe void ZeroMemory(void* ptr, nuint byteCount)
{
SpanHelpers.ClearWithoutReferences(ref *(byte*)ptr, byteCount);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static nuint GetByteCount(nuint elementCount, nuint elementSize)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,8 @@ public static void AlignedFree(void* ptr) { }
public static void Free(void* ptr) { }
[System.CLSCompliantAttribute(false)]
public static void* Realloc(void* ptr, nuint byteCount) { throw null; }
[System.CLSCompliantAttribute(false)]
public static void ZeroMemory(void* ptr, nuint byteCount) { throw null; }
}
public readonly partial struct NFloat : System.IComparable, System.IComparable<System.Runtime.InteropServices.NFloat>, System.IEquatable<System.Runtime.InteropServices.NFloat>, System.IFormattable, System.IParsable<System.Runtime.InteropServices.NFloat>, System.ISpanFormattable, System.ISpanParsable<System.Runtime.InteropServices.NFloat>, System.Numerics.IAdditionOperators<System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat>, System.Numerics.IAdditiveIdentity<System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat>, System.Numerics.IBinaryFloatingPointIeee754<System.Runtime.InteropServices.NFloat>, System.Numerics.IBinaryNumber<System.Runtime.InteropServices.NFloat>, System.Numerics.IBitwiseOperators<System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat>, System.Numerics.IComparisonOperators<System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat>, System.Numerics.IDecrementOperators<System.Runtime.InteropServices.NFloat>, System.Numerics.IDivisionOperators<System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat>, System.Numerics.IEqualityOperators<System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat>, System.Numerics.IExponentialFunctions<System.Runtime.InteropServices.NFloat>, System.Numerics.IFloatingPoint<System.Runtime.InteropServices.NFloat>, System.Numerics.IFloatingPointIeee754<System.Runtime.InteropServices.NFloat>, System.Numerics.IHyperbolicFunctions<System.Runtime.InteropServices.NFloat>, System.Numerics.IIncrementOperators<System.Runtime.InteropServices.NFloat>, System.Numerics.ILogarithmicFunctions<System.Runtime.InteropServices.NFloat>, System.Numerics.IMinMaxValue<System.Runtime.InteropServices.NFloat>, System.Numerics.IModulusOperators<System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat>, System.Numerics.IMultiplicativeIdentity<System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat>, System.Numerics.IMultiplyOperators<System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat>, System.Numerics.INumber<System.Runtime.InteropServices.NFloat>, System.Numerics.INumberBase<System.Runtime.InteropServices.NFloat>, System.Numerics.IPowerFunctions<System.Runtime.InteropServices.NFloat>, System.Numerics.IRootFunctions<System.Runtime.InteropServices.NFloat>, System.Numerics.ISignedNumber<System.Runtime.InteropServices.NFloat>, System.Numerics.ISubtractionOperators<System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat>, System.Numerics.ITrigonometricFunctions<System.Runtime.InteropServices.NFloat>, System.Numerics.IUnaryNegationOperators<System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat>, System.Numerics.IUnaryPlusOperators<System.Runtime.InteropServices.NFloat, System.Runtime.InteropServices.NFloat>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -435,5 +435,128 @@ public void ReallocSmallerToLargerTest()

NativeMemory.Free(newPtr);
}

[Theory]
[InlineData(1, 0)]
[InlineData(1, 1)]
[InlineData(1, 2)]
[InlineData(1, 3)]
[InlineData(2, 0)]
[InlineData(3, 0)]
[InlineData(4, 0)]
[InlineData(8, 0)]
[InlineData(9, 0)]
[InlineData(16, 0)]
[InlineData(16, 1)]
[InlineData(16, 3)]
[InlineData(16, 7)]
[InlineData(32, 0)]
[InlineData(64, 0)]
[InlineData(128, 0)]
[InlineData(256, 0)]
[InlineData(256, 1)]
[InlineData(256, 2)]
[InlineData(256, 3)]
[InlineData(256, 5)]
[InlineData(512, 0)]
[InlineData(547, 0)]
[InlineData(1 * 1024, 0)]
public void ZeroMemoryTest(int size, int offset)
{
byte* ptr = (byte*)NativeMemory.AlignedAlloc((nuint)(size + offset), 8);

Assert.True(ptr != null);
Assert.True((nuint)ptr % 8 == 0);

new Span<byte>(ptr, size + offset).Fill(0b10101010);

NativeMemory.ZeroMemory(ptr + offset, (nuint)size);

Assert.Equal(-1, new Span<byte>(ptr + offset, size).IndexOfAnyExcept((byte)0));

NativeMemory.AlignedFree(ptr);
}

[Theory]
[InlineData(1, 0)]
[InlineData(1, 1)]
[InlineData(1, 2)]
[InlineData(1, 3)]
[InlineData(1, 44)]
[InlineData(1, 367)]
[InlineData(2, 0)]
[InlineData(3, 0)]
[InlineData(4, 0)]
[InlineData(8, 0)]
[InlineData(9, 0)]
[InlineData(9, 2)]
[InlineData(9, 111)]
[InlineData(9, 289)]
[InlineData(16, 0)]
[InlineData(16, 1)]
[InlineData(16, 3)]
[InlineData(16, 7)]
[InlineData(32, 0)]
[InlineData(64, 0)]
[InlineData(128, 0)]
[InlineData(256, 0)]
[InlineData(256, 1)]
[InlineData(256, 2)]
[InlineData(256, 3)]
[InlineData(256, 5)]
[InlineData(256, 67)]
[InlineData(256, 143)]
public void ZeroMemoryWithExactRangeTest(int size, int offset)
{
int headLength = offset;
int bodyLength = size;
int tailLength = 512 - headLength - bodyLength;
int headOffset = 0;
int bodyOffset = headLength;
int tailOffset = headLength + bodyLength;

byte* ptr = (byte*)NativeMemory.AlignedAlloc(512, 8);

Assert.True(ptr != null);
Assert.True((nuint)ptr % 8 == 0);

new Span<byte>(ptr, 512).Fill(0b10101010);

NativeMemory.ZeroMemory(ptr + bodyOffset, (nuint)bodyLength);

Assert.Equal(-1, new Span<byte>(ptr + headOffset, headLength).IndexOfAnyExcept((byte)0b10101010));
Assert.Equal(-1, new Span<byte>(ptr + bodyOffset, bodyLength).IndexOfAnyExcept((byte)0));
Assert.Equal(-1, new Span<byte>(ptr + tailOffset, tailLength).IndexOfAnyExcept((byte)0b10101010));

NativeMemory.AlignedFree(ptr);
}

[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(167)]
public void ZeroMemoryWithSizeEqualTo0ShouldNoOpTest(int offset)
{
byte* ptr = (byte*)NativeMemory.AlignedAlloc(512, 8);

Assert.True(ptr != null);
Assert.True((nuint)ptr % 8 == 0);

new Span<byte>(ptr, 512).Fill(0b10101010);

NativeMemory.ZeroMemory(ptr + offset, 0);

Assert.Equal(-1, new Span<byte>(ptr, 512).IndexOfAnyExcept((byte)0b10101010));

NativeMemory.AlignedFree(ptr);
}

[Fact]
public void ZeroMemoryWithNullPointerAndZeroByteCountTest()
{
NativeMemory.ZeroMemory(null, 0);

// This test method just needs to check that no exceptions are thrown
}
}
}

0 comments on commit 6a00977

Please sign in to comment.