From b759ac9716a3c992aa4d22d46ab2f2443aab0a6e Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Thu, 27 May 2021 21:08:53 -0700 Subject: [PATCH] Expose Array.Clear(Array) as public API (#53388) --- .../src/System/Array.CoreCLR.cs | 7 +++- .../Cryptography/BasicSymmetricCipher.cs | 2 +- .../BasicSymmetricCipherBCrypt.cs | 2 +- .../Internal/Cryptography/HashProviderCng.cs | 2 +- .../Cryptography/UniversalCryptoDecryptor.cs | 4 +- .../System/Security/Cryptography/CngPkcs8.cs | 2 +- .../ECDiffieHellmanCng.ImportExport.cs | 4 +- .../Cryptography/ECDiffieHellmanDerivation.cs | 6 +-- .../ECDiffieHellmanSecurityTransforms.cs | 2 +- .../Common/tests/Tests/System/StringTests.cs | 2 +- .../Collections/Concurrent/ConcurrentBag.cs | 2 +- .../Immutable/ImmutableExtensions.cs | 4 +- .../tests/FileStream/ReadAsync.cs | 2 +- .../tests/MemoryMappedViewStream.Tests.cs | 2 +- .../System.Linq/tests/SelectManyTests.cs | 6 +-- .../System.Memory/tests/Span/Fill.cs | 2 +- .../src/System/Xml/XmlBinaryReaderSession.cs | 2 +- .../src/System/Xml/XmlBinaryWriterSession.cs | 2 +- .../System/Xml/BinaryXml/XmlBinaryReader.cs | 2 +- .../ConstructorInfoInvokeArrayTests.cs | 16 ++++---- .../tests/System/Random.cs | 4 +- .../BigIntegerCalculator.FastReducer.cs | 2 +- .../System.Runtime/ref/System.Runtime.cs | 1 + .../System.Runtime/tests/System/ArrayTests.cs | 40 ++++++++++++++++--- .../Cryptography/HashProviderDispenser.OSX.cs | 2 +- .../Cryptography/Rfc2898DeriveBytes.cs | 6 +-- .../Cryptography/PasswordDeriveBytes.cs | 8 ++-- .../Security/Cryptography/CryptoStream.cs | 12 +++--- .../Cryptography/KeyedHashAlgorithm.cs | 2 +- .../Cryptography/SymmetricAlgorithm.cs | 4 +- .../src/Internal/Cryptography/Helpers.cs | 2 +- .../tests/CertTests.cs | 4 +- .../tests/EncodingTestHelpers.cs | 2 +- .../src/System/Array.Mono.cs | 2 +- 34 files changed, 100 insertions(+), 64 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs index 100fafba5a95f..3c4f41c81e172 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs @@ -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) + /// + /// Clears the contents of an array. + /// + /// The array to clear. + /// is null. + public static unsafe void Clear(Array array) { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); diff --git a/src/libraries/Common/src/Internal/Cryptography/BasicSymmetricCipher.cs b/src/libraries/Common/src/Internal/Cryptography/BasicSymmetricCipher.cs index 33b5e8114e54f..542955e53d743 100644 --- a/src/libraries/Common/src/Internal/Cryptography/BasicSymmetricCipher.cs +++ b/src/libraries/Common/src/Internal/Cryptography/BasicSymmetricCipher.cs @@ -47,7 +47,7 @@ protected virtual void Dispose(bool disposing) { if (IV != null) { - Array.Clear(IV, 0, IV.Length); + Array.Clear(IV); IV = null; } } diff --git a/src/libraries/Common/src/Internal/Cryptography/BasicSymmetricCipherBCrypt.cs b/src/libraries/Common/src/Internal/Cryptography/BasicSymmetricCipherBCrypt.cs index 5222af23672e7..59d984f5fec49 100644 --- a/src/libraries/Common/src/Internal/Cryptography/BasicSymmetricCipherBCrypt.cs +++ b/src/libraries/Common/src/Internal/Cryptography/BasicSymmetricCipherBCrypt.cs @@ -52,7 +52,7 @@ protected override void Dispose(bool disposing) _currentIv = null; if (currentIv != null) { - Array.Clear(currentIv, 0, currentIv.Length); + Array.Clear(currentIv); } } diff --git a/src/libraries/Common/src/Internal/Cryptography/HashProviderCng.cs b/src/libraries/Common/src/Internal/Cryptography/HashProviderCng.cs index 4644bf61e3575..3b864790b2525 100644 --- a/src/libraries/Common/src/Internal/Cryptography/HashProviderCng.cs +++ b/src/libraries/Common/src/Internal/Cryptography/HashProviderCng.cs @@ -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); } } } diff --git a/src/libraries/Common/src/Internal/Cryptography/UniversalCryptoDecryptor.cs b/src/libraries/Common/src/Internal/Cryptography/UniversalCryptoDecryptor.cs index 73846de86212d..3f050ff1eda72 100644 --- a/src/libraries/Common/src/Internal/Cryptography/UniversalCryptoDecryptor.cs +++ b/src/libraries/Common/src/Internal/Cryptography/UniversalCryptoDecryptor.cs @@ -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); } } @@ -181,7 +181,7 @@ private void Reset() { if (_heldoverCipher != null) { - Array.Clear(_heldoverCipher, 0, _heldoverCipher.Length); + Array.Clear(_heldoverCipher); _heldoverCipher = null; } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/CngPkcs8.cs b/src/libraries/Common/src/System/Security/Cryptography/CngPkcs8.cs index aede8bd8958db..e6d6ef01972eb 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/CngPkcs8.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/CngPkcs8.cs @@ -427,7 +427,7 @@ private static AsnWriter RewriteEncryptedPkcs8PrivateKey( } finally { - Array.Clear(ecParameters.D!, 0, ecParameters.D!.Length); + Array.Clear(ecParameters.D!); } } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/ECDiffieHellmanCng.ImportExport.cs b/src/libraries/Common/src/System/Security/Cryptography/ECDiffieHellmanCng.ImportExport.cs index 6ffe9e7e518d2..a18e08635b934 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/ECDiffieHellmanCng.ImportExport.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/ECDiffieHellmanCng.ImportExport.cs @@ -80,7 +80,7 @@ public override ECParameters ExportExplicitParameters(bool includePrivateParamet } finally { - Array.Clear(blob, 0, blob.Length); + Array.Clear(blob); } } @@ -111,7 +111,7 @@ public override ECParameters ExportParameters(bool includePrivateParameters) { if (blob != null) { - Array.Clear(blob, 0, blob.Length); + Array.Clear(blob); } } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/ECDiffieHellmanDerivation.cs b/src/libraries/Common/src/System/Security/Cryptography/ECDiffieHellmanDerivation.cs index 0fd7309f73e15..f78eaa8067100 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/ECDiffieHellmanDerivation.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/ECDiffieHellmanDerivation.cs @@ -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); } } } @@ -166,7 +166,7 @@ internal static unsafe byte[] DeriveKeyTls( } finally { - Array.Clear(secretAgreement, 0, secretAgreement.Length); + Array.Clear(secretAgreement); } } } @@ -255,7 +255,7 @@ private static unsafe void PHash( } finally { - Array.Clear(secretTmp, 0, secretTmp.Length); + Array.Clear(secretTmp); } } #endif diff --git a/src/libraries/Common/src/System/Security/Cryptography/ECDiffieHellmanSecurityTransforms.cs b/src/libraries/Common/src/System/Security/Cryptography/ECDiffieHellmanSecurityTransforms.cs index 5b85e6e5aa014..214bc96f8b0e9 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/ECDiffieHellmanSecurityTransforms.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/ECDiffieHellmanSecurityTransforms.cs @@ -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; diff --git a/src/libraries/Common/tests/Tests/System/StringTests.cs b/src/libraries/Common/tests/Tests/System/StringTests.cs index 91ff8a5dcd3c9..38555b9ad4da8 100644 --- a/src/libraries/Common/tests/Tests/System/StringTests.cs +++ b/src/libraries/Common/tests/Tests/System/StringTests.cs @@ -510,7 +510,7 @@ public static void CopyTo_Span(string s, int destinationLength) Assert.Equal(s, new Span(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(destination, 0, s.Length).ToString()); diff --git a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentBag.cs b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentBag.cs index 0328b9f0e526f..b4351d9864565 100644 --- a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentBag.cs +++ b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentBag.cs @@ -860,7 +860,7 @@ internal void LocalClear() { _headIndex = _tailIndex = StartIndex; _addTakeCount = _stealCount = 0; - Array.Clear(_array, 0, _array.Length); + Array.Clear(_array); } } } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.cs index 428c71f13768b..006a26addc1fd 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.cs @@ -64,9 +64,9 @@ internal static IOrderedCollection AsOrderedCollection(this IEnumerable /// /// Clears the specified stack. For empty stacks, it avoids the call to , which - /// avoids a call into the runtime's implementation of , helping performance, + /// avoids a call into the runtime's implementation of , helping performance, /// in particular around inlining. typically gets inlined by today's JIT, while - /// and typically don't. + /// and typically don't. /// /// Specifies the type of data in the stack to be cleared. /// The stack to clear. diff --git a/src/libraries/System.IO.FileSystem/tests/FileStream/ReadAsync.cs b/src/libraries/System.IO.FileSystem/tests/FileStream/ReadAsync.cs index ceea76e50dd9e..ef4458ef7f45b 100644 --- a/src/libraries/System.IO.FileSystem/tests/FileStream/ReadAsync.cs +++ b/src/libraries/System.IO.FileSystem/tests/FileStream/ReadAsync.cs @@ -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))); diff --git a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs index 5874800d73f44..5903d4756ed97 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs @@ -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); diff --git a/src/libraries/System.Linq/tests/SelectManyTests.cs b/src/libraries/System.Linq/tests/SelectManyTests.cs index 50d97f07bb291..14fd1dc62e65d 100644 --- a/src/libraries/System.Linq/tests/SelectManyTests.cs +++ b/src/libraries/System.Linq/tests/SelectManyTests.cs @@ -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(); diff --git a/src/libraries/System.Memory/tests/Span/Fill.cs b/src/libraries/System.Memory/tests/Span/Fill.cs index c6741219aad93..71ea23196584e 100644 --- a/src/libraries/System.Memory/tests/Span/Fill.cs +++ b/src/libraries/System.Memory/tests/Span/Fill.cs @@ -189,7 +189,7 @@ static void RunTest(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); } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryReaderSession.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryReaderSession.cs index db7c46cd4c5a9..ef384ccfdb015 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryReaderSession.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryReaderSession.cs @@ -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(); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryWriterSession.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryWriterSession.cs index 6ee7fa1614ab4..5a26c4d354173 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryWriterSession.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryWriterSession.cs @@ -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(); } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/BinaryXml/XmlBinaryReader.cs b/src/libraries/System.Private.Xml/src/System/Xml/BinaryXml/XmlBinaryReader.cs index 36d739c9dae89..f2c53a5ca2209 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/BinaryXml/XmlBinaryReader.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/BinaryXml/XmlBinaryReader.cs @@ -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() diff --git a/src/libraries/System.Reflection.TypeExtensions/tests/ConstructorInfo/ConstructorInfoInvokeArrayTests.cs b/src/libraries/System.Reflection.TypeExtensions/tests/ConstructorInfo/ConstructorInfoInvokeArrayTests.cs index f5f6d36e3939b..a050476cee765 100644 --- a/src/libraries/System.Reflection.TypeExtensions/tests/ConstructorInfo/ConstructorInfoInvokeArrayTests.cs +++ b/src/libraries/System.Reflection.TypeExtensions/tests/ConstructorInfo/ConstructorInfoInvokeArrayTests.cs @@ -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++) @@ -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++) @@ -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++) @@ -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++) @@ -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++) diff --git a/src/libraries/System.Runtime.Extensions/tests/System/Random.cs b/src/libraries/System.Runtime.Extensions/tests/System/Random.cs index 1cc1ccc21ec97..5a5d95b123b3e 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/Random.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/Random.cs @@ -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)buffer); Assert.Contains(buffer, b => b != 0); } diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigIntegerCalculator.FastReducer.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigIntegerCalculator.FastReducer.cs index d19b87b2f943f..8731794b40299 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigIntegerCalculator.FastReducer.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigIntegerCalculator.FastReducer.cs @@ -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) { diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 224a13e6abffd..ba30ccf66a0aa 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -325,6 +325,7 @@ internal Array() { } public static int BinarySearch(T[] array, int index, int length, T value, System.Collections.Generic.IComparer? comparer) { throw null; } public static int BinarySearch(T[] array, T value) { throw null; } public static int BinarySearch(T[] array, T value, System.Collections.Generic.IComparer? 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) { } diff --git a/src/libraries/System.Runtime/tests/System/ArrayTests.cs b/src/libraries/System.Runtime/tests/System/ArrayTests.cs index bada013ea1b02..04bb40e2aeb2a 100644 --- a/src/libraries/System.Runtime/tests/System/ArrayTests.cs +++ b/src/libraries/System.Runtime/tests/System/ArrayTests.cs @@ -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] @@ -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++) { @@ -891,6 +914,7 @@ public static void Clear_Struct_WithReferenceAndValueTypeFields_Array() [Fact] public static void Clear_Invalid() { + AssertExtensions.Throws("array", () => Array.Clear(null)); // Array is null AssertExtensions.Throws("array", () => Array.Clear(null, 0, 0)); // Array is null Assert.Throws(() => Array.Clear(new int[10], -1, 0)); // Index < 0 @@ -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]); } diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.OSX.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.OSX.cs index 3a9901337f9c6..bb14bc8b868ee 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.OSX.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.OSX.cs @@ -157,7 +157,7 @@ public override void Dispose(bool disposing) if (disposing) { _ctx?.Dispose(); - Array.Clear(_key, 0, _key.Length); + Array.Clear(_key); } } diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs index 2648b2635bbc3..bc01e7d9780a7 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs @@ -163,9 +163,9 @@ protected override void Dispose(bool disposing) } if (_buffer != null) - Array.Clear(_buffer, 0, _buffer.Length); + Array.Clear(_buffer); if (_salt != null) - Array.Clear(_salt, 0, _salt.Length); + Array.Clear(_salt); } base.Dispose(disposing); } @@ -260,7 +260,7 @@ private HMAC OpenHmac(byte[] password) private void Initialize() { if (_buffer != null) - Array.Clear(_buffer, 0, _buffer.Length); + Array.Clear(_buffer); _buffer = new byte[_blockSize]; _block = 0; _startIndex = _endIndex = 0; diff --git a/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/PasswordDeriveBytes.cs b/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/PasswordDeriveBytes.cs index 82a4db632239f..db227e67a5d49 100644 --- a/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/PasswordDeriveBytes.cs +++ b/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/PasswordDeriveBytes.cs @@ -177,22 +177,22 @@ protected override void Dispose(bool disposing) if (_baseValue != null) { - Array.Clear(_baseValue, 0, _baseValue.Length); + Array.Clear(_baseValue); } if (_extra != null) { - Array.Clear(_extra, 0, _extra.Length); + Array.Clear(_extra); } if (_password != null) { - Array.Clear(_password, 0, _password.Length); + Array.Clear(_password); } if (_salt != null) { - Array.Clear(_salt, 0, _salt.Length); + Array.Clear(_salt); } } } diff --git a/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoStream.cs b/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoStream.cs index 7b2796584b3bc..c023c9068f51a 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoStream.cs +++ b/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoStream.cs @@ -162,9 +162,9 @@ private async ValueTask FlushFinalBlockAsync(bool useAsync, CancellationToken ca // zeroize plain text material before returning if (_inputBuffer != null) - Array.Clear(_inputBuffer, 0, _inputBuffer.Length); + Array.Clear(_inputBuffer); if (_outputBuffer != null) - Array.Clear(_outputBuffer, 0, _outputBuffer.Length); + Array.Clear(_outputBuffer); } public override void Flush() @@ -803,9 +803,9 @@ protected override void Dispose(bool disposing) _finalBlockTransformed = true; // we need to clear all the internal buffers if (_inputBuffer != null) - Array.Clear(_inputBuffer, 0, _inputBuffer.Length); + Array.Clear(_inputBuffer); if (_outputBuffer != null) - Array.Clear(_outputBuffer, 0, _outputBuffer.Length); + Array.Clear(_outputBuffer); _inputBuffer = null; _outputBuffer = null; @@ -850,12 +850,12 @@ private async ValueTask DisposeAsyncCore() // we need to clear all the internal buffers if (_inputBuffer != null) { - Array.Clear(_inputBuffer, 0, _inputBuffer.Length); + Array.Clear(_inputBuffer); } if (_outputBuffer != null) { - Array.Clear(_outputBuffer, 0, _outputBuffer.Length); + Array.Clear(_outputBuffer); } _inputBuffer = null; diff --git a/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/KeyedHashAlgorithm.cs b/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/KeyedHashAlgorithm.cs index cefdd28244907..7cade9ddbceb8 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/KeyedHashAlgorithm.cs +++ b/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/KeyedHashAlgorithm.cs @@ -38,7 +38,7 @@ protected override void Dispose(bool disposing) { if (KeyValue != null) { - Array.Clear(KeyValue, 0, KeyValue.Length); + Array.Clear(KeyValue); } KeyValue = null!; } diff --git a/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/SymmetricAlgorithm.cs b/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/SymmetricAlgorithm.cs index ec47957a10231..c140062b697f6 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/SymmetricAlgorithm.cs +++ b/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/SymmetricAlgorithm.cs @@ -199,12 +199,12 @@ protected virtual void Dispose(bool disposing) { if (KeyValue != null) { - Array.Clear(KeyValue, 0, KeyValue.Length); + Array.Clear(KeyValue); KeyValue = null; } if (IVValue != null) { - Array.Clear(IVValue, 0, IVValue.Length); + Array.Clear(IVValue); IVValue = null; } } diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Helpers.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Helpers.cs index 77f16bc21f02e..731440b7c7726 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Helpers.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Helpers.cs @@ -343,7 +343,7 @@ internal static PinAndClear Track(byte[] data) public void Dispose() { - Array.Clear(_data, 0, _data.Length); + Array.Clear(_data); _gcHandle.Free(); } } diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/CertTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/CertTests.cs index de985bfb61c83..24363f1ab4e42 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/CertTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/CertTests.cs @@ -450,7 +450,7 @@ public static void MutateDistinguishedName_IssuerName_DoesNotImpactIssuer() using (X509Certificate2 cert = new X509Certificate2(TestData.MsCertificate)) { byte[] issuerBytes = cert.IssuerName.RawData; - Array.Clear(issuerBytes, 0, issuerBytes.Length); + Array.Clear(issuerBytes); Assert.Equal("CN=Microsoft Code Signing PCA, O=Microsoft Corporation, L=Redmond, S=Washington, C=US", cert.Issuer); } } @@ -461,7 +461,7 @@ public static void MutateDistinguishedName_SubjectName_DoesNotImpactSubject() using (X509Certificate2 cert = new X509Certificate2(TestData.MsCertificate)) { byte[] subjectBytes = cert.SubjectName.RawData; - Array.Clear(subjectBytes, 0, subjectBytes.Length); + Array.Clear(subjectBytes); Assert.Equal("CN=Microsoft Corporation, OU=MOPR, O=Microsoft Corporation, L=Redmond, S=Washington, C=US", cert.Subject); } } diff --git a/src/libraries/System.Text.Encoding/tests/EncodingTestHelpers.cs b/src/libraries/System.Text.Encoding/tests/EncodingTestHelpers.cs index 4799b54718d0b..f049afdf196f3 100644 --- a/src/libraries/System.Text.Encoding/tests/EncodingTestHelpers.cs +++ b/src/libraries/System.Text.Encoding/tests/EncodingTestHelpers.cs @@ -264,7 +264,7 @@ static void GetBytes_NetCoreApp(Encoding encoding, string chars, int index, int VerifyGetBytes(stringResultAdvanced, 0, stringResultAdvanced.Length, new byte[expected.Length], expected); // Use GetBytes(ReadOnlySpan, Span) - Array.Clear(stringResultAdvanced, 0, stringResultAdvanced.Length); + Array.Clear(stringResultAdvanced); Assert.Equal(expected.Length, encoding.GetBytes(chars.AsSpan(index, count), (Span)stringResultAdvanced)); VerifyGetBytes(stringResultAdvanced, 0, stringResultAdvanced.Length, new byte[expected.Length], expected); diff --git a/src/mono/System.Private.CoreLib/src/System/Array.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Array.Mono.cs index 75f3ecd703661..7926abd1b7218 100644 --- a/src/mono/System.Private.CoreLib/src/System/Array.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Array.Mono.cs @@ -62,7 +62,7 @@ public int Rank get => Rank; } - internal static unsafe void Clear(Array array) + public static unsafe void Clear(Array array) { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);