Skip to content

Commit

Permalink
Expose Array.Clear(Array) as public API (#53388)
Browse files Browse the repository at this point in the history
  • Loading branch information
GrabYourPitchforks authored May 28, 2021
1 parent dbc55bf commit b759ac9
Show file tree
Hide file tree
Showing 34 changed files with 100 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,12 @@ public static void ConstrainedCopy(Array sourceArray, int sourceIndex, Array des
Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, length, reliable: true);
}

internal static unsafe void Clear(Array array)
/// <summary>
/// Clears the contents of an array.
/// </summary>
/// <param name="array">The array to clear.</param>
/// <exception cref="ArgumentNullException"><paramref name="array"/> is null.</exception>
public static unsafe void Clear(Array array)
{
if (array == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ protected virtual void Dispose(bool disposing)
{
if (IV != null)
{
Array.Clear(IV, 0, IV.Length);
Array.Clear(IV);
IV = null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ protected override void Dispose(bool disposing)
_currentIv = null;
if (currentIv != null)
{
Array.Clear(currentIv, 0, currentIv.Length);
Array.Clear(currentIv);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public sealed override void Dispose(bool disposing)
{
byte[] key = _key;
_key = null;
Array.Clear(key, 0, key.Length);
Array.Clear(key);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ protected sealed override void Dispose(bool disposing)
_heldoverCipher = null;
if (heldoverCipher != null)
{
Array.Clear(heldoverCipher, 0, heldoverCipher.Length);
Array.Clear(heldoverCipher);
}
}

Expand All @@ -181,7 +181,7 @@ private void Reset()
{
if (_heldoverCipher != null)
{
Array.Clear(_heldoverCipher, 0, _heldoverCipher.Length);
Array.Clear(_heldoverCipher);
_heldoverCipher = null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ private static AsnWriter RewriteEncryptedPkcs8PrivateKey(
}
finally
{
Array.Clear(ecParameters.D!, 0, ecParameters.D!.Length);
Array.Clear(ecParameters.D!);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public override ECParameters ExportExplicitParameters(bool includePrivateParamet
}
finally
{
Array.Clear(blob, 0, blob.Length);
Array.Clear(blob);
}
}

Expand Down Expand Up @@ -111,7 +111,7 @@ public override ECParameters ExportParameters(bool includePrivateParameters)
{
if (blob != null)
{
Array.Clear(blob, 0, blob.Length);
Array.Clear(blob);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ internal static unsafe byte[] DeriveKeyFromHmac(
// If useSecretAsKey is false then hmacKey is owned by the caller, not ours to clear.
if (useSecretAsKey)
{
Array.Clear(hmacKey, 0, hmacKey.Length);
Array.Clear(hmacKey);
}
}
}
Expand Down Expand Up @@ -166,7 +166,7 @@ internal static unsafe byte[] DeriveKeyTls(
}
finally
{
Array.Clear(secretAgreement, 0, secretAgreement.Length);
Array.Clear(secretAgreement);
}
}
}
Expand Down Expand Up @@ -255,7 +255,7 @@ private static unsafe void PHash(
}
finally
{
Array.Clear(secretTmp, 0, secretTmp.Length);
Array.Clear(secretTmp);
}
}
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ public override byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey
else
{
hasher.AppendData(secret);
Array.Clear(secret, 0, secret.Length);
Array.Clear(secret);
}

return null;
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/Common/tests/Tests/System/StringTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ public static void CopyTo_Span(string s, int destinationLength)
Assert.Equal(s, new Span<char>(destination, 0, s.Length).ToString());
Assert.All(destination.AsSpan(s.Length).ToArray(), c => Assert.Equal(0, c));

Array.Clear(destination, 0, destination.Length);
Array.Clear(destination);

Assert.True(s.TryCopyTo(destination));
Assert.Equal(s, new Span<char>(destination, 0, s.Length).ToString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,7 @@ internal void LocalClear()
{
_headIndex = _tailIndex = StartIndex;
_addTakeCount = _stealCount = 0;
Array.Clear(_array, 0, _array.Length);
Array.Clear(_array);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ internal static IOrderedCollection<T> AsOrderedCollection<T>(this IEnumerable<T>

/// <summary>
/// Clears the specified stack. For empty stacks, it avoids the call to <see cref="Stack{T}.Clear"/>, which
/// avoids a call into the runtime's implementation of <see cref="Array.Clear"/>, helping performance,
/// avoids a call into the runtime's implementation of <see cref="Array.Clear(Array, int, int)"/>, helping performance,
/// in particular around inlining. <see cref="Stack{T}.Count"/> typically gets inlined by today's JIT, while
/// <see cref="Stack{T}.Clear"/> and <see cref="Array.Clear"/> typically don't.
/// <see cref="Stack{T}.Clear"/> and <see cref="Array.Clear(Array, int, int)"/> typically don't.
/// </summary>
/// <typeparam name="T">Specifies the type of data in the stack to be cleared.</typeparam>
/// <param name="stack">The stack to clear.</param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public async Task ReadAsyncBufferedCompletesSynchronously()
Assert.Equal(TestBuffer.Length, await ReadAsync(fs, buffer, 0, buffer.Length));
Assert.Equal(TestBuffer, buffer);

Array.Clear(buffer, 0, buffer.Length);
Array.Clear(buffer);

// read should now complete synchronously since it is serviced by the read buffer filled in the first request
Assert.Equal(TestBuffer.Length, FSAssert.CompletesSynchronously(ReadAsync(fs, buffer, 0, buffer.Length)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ public void AllReadWriteMethods(long offset, long size)
s.Position = s.Length - data.Length;
s.Write(data, 0, data.Length);
s.Position = s.Length - data.Length;
Array.Clear(data, 0, data.Length);
Array.Clear(data);
Assert.Equal(3, s.Read(data, 0, data.Length));
Assert.Equal(new byte[] { 1, 2, 3 }, data);

Expand Down
6 changes: 3 additions & 3 deletions src/libraries/System.Linq/tests/SelectManyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -509,19 +509,19 @@ public void EvaluateSelectorOncePerItem(int count)
Assert.Equal(Enumerable.Repeat(0, timesCalledMap.Length - index - 1), timesCalledMap.Skip(index + 1));
}

Array.Clear(timesCalledMap, 0, timesCalledMap.Length);
Array.Clear(timesCalledMap);

// ToArray
iterator.ToArray();
Assert.Equal(Enumerable.Repeat(1, timesCalledMap.Length), timesCalledMap);

Array.Clear(timesCalledMap, 0, timesCalledMap.Length);
Array.Clear(timesCalledMap);

// ToList
iterator.ToList();
Assert.Equal(Enumerable.Repeat(1, timesCalledMap.Length), timesCalledMap);

Array.Clear(timesCalledMap, 0, timesCalledMap.Length);
Array.Clear(timesCalledMap);

// ToHashSet
iterator.ToHashSet();
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/System.Memory/tests/Span/Fill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ static void RunTest<T>(T value)
arr.AsSpan(0, i).Fill(value);
Assert.Equal(Enumerable.Repeat(value, i), arr.Take(i)); // first i entries should've been populated with 'value'
Assert.Equal(Enumerable.Repeat(default(T), arr.Length - i), arr.Skip(i)); // remaining entries should contain default(T)
Array.Clear(arr, 0, arr.Length);
Array.Clear(arr);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public bool TryLookup(XmlDictionaryString value, [NotNullWhen(true)] out XmlDict
public void Clear()
{
if (_strings != null)
Array.Clear(_strings, 0, _strings.Length);
Array.Clear(_strings);

if (_stringDict != null)
_stringDict.Clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public void Clear()
{
_now = 0;
_listCount = 0;
Array.Clear(_list, 0, _list.Length);
Array.Clear(_list);
if (_dictionary != null)
_dictionary.Clear();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1987,7 +1987,7 @@ private void NameFlush()
{
_symbolTables.symCount = _symbolTables.qnameCount = 1;
Array.Clear(_symbolTables.symtable, 1, _symbolTables.symtable.Length - 1);
Array.Clear(_symbolTables.qnametable, 0, _symbolTables.qnametable.Length);
Array.Clear(_symbolTables.qnametable);
}

private void SkipExtn()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public void Invoke_1DArrayConstructor()
int[] invalidLowerBounds = new int[] { -20, 0, 20 };
if (!PlatformDetection.IsNonZeroLowerBoundArraySupported)
{
Array.Clear(invalidLowerBounds, 0, invalidLowerBounds.Length);
Array.Clear(invalidLowerBounds);
}
int[] invalidLengths = new int[] { -100, -9, -1 };
for (int j = 0; j < invalidLengths.Length; j++)
Expand All @@ -81,7 +81,7 @@ public void Invoke_1DArrayConstructor()
int[] validLowerBounds = new int[] { 0, 1, -1, 2, -3, 5, -10, 99, 100 };
if (!PlatformDetection.IsNonZeroLowerBoundArraySupported)
{
Array.Clear(validLowerBounds, 0, validLowerBounds.Length);
Array.Clear(validLowerBounds);
}
int[] validLengths = new int[] { 0, 1, 3, 2, 3, 5, 10, 99, 0 };
for (int j = 0; j < validLengths.Length; j++)
Expand Down Expand Up @@ -144,8 +144,8 @@ public void Invoke_2DArrayConstructor()

if (!PlatformDetection.IsNonZeroLowerBoundArraySupported)
{
Array.Clear(invalidLowerBounds1, 0, invalidLowerBounds1.Length);
Array.Clear(invalidLowerBounds2, 0, invalidLowerBounds2.Length);
Array.Clear(invalidLowerBounds1);
Array.Clear(invalidLowerBounds2);
}

for (int j = 0; j < invalidLengths3.Length; j++)
Expand Down Expand Up @@ -179,8 +179,8 @@ public void Invoke_2DArrayConstructor()

if (!PlatformDetection.IsNonZeroLowerBoundArraySupported)
{
Array.Clear(validLowerBounds1, 0, validLowerBounds1.Length);
Array.Clear(validLowerBounds2, 0, validLowerBounds2.Length);
Array.Clear(validLowerBounds1);
Array.Clear(validLowerBounds2);
}

for (int j = 0; j < validLengths1.Length; j++)
Expand All @@ -201,8 +201,8 @@ public void Invoke_2DArrayConstructor()

if (!PlatformDetection.IsNonZeroLowerBoundArraySupported)
{
Array.Clear(validLowerBounds1, 0, validLowerBounds1.Length);
Array.Clear(validLowerBounds2, 0, validLowerBounds2.Length);
Array.Clear(validLowerBounds1);
Array.Clear(validLowerBounds2);
}

for (int j = 0; j < validLengths1.Length; j++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -470,11 +470,11 @@ public void Shared_ParallelUsage()
Assert.InRange(Random.Shared.NextSingle(), 0.0f, 1.0f);
Assert.InRange(Random.Shared.NextDouble(), 0.0, 1.0);
Array.Clear(buffer, 0, buffer.Length);
Array.Clear(buffer);
Random.Shared.NextBytes(buffer);
Assert.Contains(buffer, b => b != 0);
Array.Clear(buffer, 0, buffer.Length);
Array.Clear(buffer);
Random.Shared.NextBytes((Span<byte>)buffer);
Assert.Contains(buffer, b => b != 0);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ private static unsafe int DivMul(uint[] left, int leftLength,
// preceding division by 2^(32*k). To spare memory allocations
// we write the result to an already allocated memory.

Array.Clear(bits, 0, bits.Length);
Array.Clear(bits);

if (leftLength > k)
{
Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ internal Array() { }
public static int BinarySearch<T>(T[] array, int index, int length, T value, System.Collections.Generic.IComparer<T>? comparer) { throw null; }
public static int BinarySearch<T>(T[] array, T value) { throw null; }
public static int BinarySearch<T>(T[] array, T value, System.Collections.Generic.IComparer<T>? comparer) { throw null; }
public static void Clear(System.Array array) { }
public static void Clear(System.Array array, int index, int length) { }
public object Clone() { throw null; }
public static void ConstrainedCopy(System.Array sourceArray, int sourceIndex, System.Array destinationArray, int destinationIndex, int length) { }
Expand Down
40 changes: 35 additions & 5 deletions src/libraries/System.Runtime/tests/System/ArrayTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -831,14 +831,20 @@ public static void Clear(Array array, int index, int length, Array expected)
{
if (index == 0 && length == array.Length)
{
// Use IList.Clear()
// Use Array.Clear()
Array arrayClone1 = (Array)array.Clone();
((IList)arrayClone1).Clear();
Array.Clear(arrayClone1);
Assert.Equal(expected, arrayClone1);

// Use IList.Clear()
Array arrayClone2 = (Array)array.Clone();
((IList)arrayClone2).Clear();
Assert.Equal(expected, arrayClone2);
}
Array arrayClone2 = (Array)array.Clone();
Array.Clear(arrayClone2, index, length);
Assert.Equal(expected, arrayClone2);

Array arrayClone3 = (Array)array.Clone();
Array.Clear(arrayClone3, index, length);
Assert.Equal(expected, arrayClone3);
}

[Fact]
Expand All @@ -853,6 +859,23 @@ public static void Clear_Struct_WithReferenceAndValueTypeFields_Array()
new NonGenericStruct { x = 5, s = "Hello", z = 6 }
};

Array.Clear(array);
for (int i = 0; i < array.Length; i++)
{
Assert.Equal(0, array[i].x);
Assert.Null(array[i].s);
Assert.Equal(0, array[i].z);
}

array = new NonGenericStruct[]
{
new NonGenericStruct { x = 1, s = "Hello", z = 2 },
new NonGenericStruct { x = 2, s = "Hello", z = 3 },
new NonGenericStruct { x = 3, s = "Hello", z = 4 },
new NonGenericStruct { x = 4, s = "Hello", z = 5 },
new NonGenericStruct { x = 5, s = "Hello", z = 6 }
};

Array.Clear(array, 0, 5);
for (int i = 0; i < array.Length; i++)
{
Expand Down Expand Up @@ -891,6 +914,7 @@ public static void Clear_Struct_WithReferenceAndValueTypeFields_Array()
[Fact]
public static void Clear_Invalid()
{
AssertExtensions.Throws<ArgumentNullException>("array", () => Array.Clear(null)); // Array is null
AssertExtensions.Throws<ArgumentNullException>("array", () => Array.Clear(null, 0, 0)); // Array is null

Assert.Throws<IndexOutOfRangeException>(() => Array.Clear(new int[10], -1, 0)); // Index < 0
Expand Down Expand Up @@ -4675,8 +4699,14 @@ public static void Clear_LargeMultiDimensionalArray()
}

short[,] a = AllocateLargeMDArray(2, 2_000_000_000);

// Test 1: use Array.Clear
a[1, 1_999_999_999] = 0x1234;
Array.Clear(a);
Assert.Equal(0, a[1, 1_999_999_999]);

// Test 2: use IList.Clear
a[1, 1_999_999_999] = 0x1234;
((IList)a).Clear();
Assert.Equal(0, a[1, 1_999_999_999]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public override void Dispose(bool disposing)
if (disposing)
{
_ctx?.Dispose();
Array.Clear(_key, 0, _key.Length);
Array.Clear(_key);
}
}

Expand Down
Loading

0 comments on commit b759ac9

Please sign in to comment.