From 17f5167d75bba8d53ed6a276f010ac51999f7983 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Fri, 27 Nov 2020 10:47:45 +0000 Subject: [PATCH] Ensure BitArray fill operations do not set bits out of range (#45223) * ensure BitArray fill operation does not produce dirty bits * Update BitArray BinaryFormatter expected blob --- .../src/System/Collections/BitArray.cs | 18 ++++++++++++++++++ .../tests/BitArray/BitArray_CtorTests.cs | 11 +++++++++++ .../tests/BitArray/BitArray_GetSetTests.cs | 12 ++++++++++++ .../tests/BinaryFormatterTestData.cs | 2 +- 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Collections/src/System/Collections/BitArray.cs b/src/libraries/System.Collections/src/System/Collections/BitArray.cs index 9eed0c8150c..1fddd453b92 100644 --- a/src/libraries/System.Collections/src/System/Collections/BitArray.cs +++ b/src/libraries/System.Collections/src/System/Collections/BitArray.cs @@ -52,6 +52,13 @@ public BitArray(int length, bool defaultValue) if (defaultValue) { m_array.AsSpan().Fill(-1); + + // clear high bit values in the last int + Div32Rem(length, out int extraBits); + if (extraBits > 0) + { + m_array[^1] = (1 << extraBits) - 1; + } } _version = 0; @@ -337,9 +344,20 @@ public void SetAll(bool value) int arrayLength = GetInt32ArrayLengthFromBitLength(Length); Span span = m_array.AsSpan(0, arrayLength); if (value) + { span.Fill(-1); + + // clear high bit values in the last int + Div32Rem(m_length, out int extraBits); + if (extraBits > 0) + { + span[^1] &= (1 << extraBits) - 1; + } + } else + { span.Clear(); + } _version++; } diff --git a/src/libraries/System.Collections/tests/BitArray/BitArray_CtorTests.cs b/src/libraries/System.Collections/tests/BitArray/BitArray_CtorTests.cs index 8ee19e44abe..199b44cd04a 100644 --- a/src/libraries/System.Collections/tests/BitArray/BitArray_CtorTests.cs +++ b/src/libraries/System.Collections/tests/BitArray/BitArray_CtorTests.cs @@ -66,6 +66,17 @@ public static void Ctor_Int_Bool(int length, bool defaultValue) Assert.False(collection.IsSynchronized); } + [Fact] + public static void Ctor_Int_Bool_ShouldNotLeaveDirtyBits() + { + BitArray bitArray = new BitArray(33, true); + bitArray.RightShift(31); + + Assert.True(bitArray[0]); + Assert.True(bitArray[1]); + Assert.False(bitArray[2]); + } + [Fact] public static void Ctor_Int_NegativeLength_ThrowsArgumentOutOfRangeException() { diff --git a/src/libraries/System.Collections/tests/BitArray/BitArray_GetSetTests.cs b/src/libraries/System.Collections/tests/BitArray/BitArray_GetSetTests.cs index c2ec1ea9f72..42d1fc35426 100644 --- a/src/libraries/System.Collections/tests/BitArray/BitArray_GetSetTests.cs +++ b/src/libraries/System.Collections/tests/BitArray/BitArray_GetSetTests.cs @@ -91,6 +91,18 @@ public static void SetAll(int size, bool defaultValue) } } + [Fact] + public static void SetAll_ShouldNotLeaveDirtyBits() + { + BitArray bitArray = new BitArray(33, false); + bitArray.SetAll(true); + bitArray.RightShift(31); + + Assert.True(bitArray[0]); + Assert.True(bitArray[1]); + Assert.False(bitArray[2]); + } + public static IEnumerable GetEnumerator_Data() { foreach (int size in new[] { 0, 1, BitsPerByte, BitsPerByte + 1, BitsPerInt32, BitsPerInt32 + 1 }) diff --git a/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs b/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs index 54af864c8c4..22a9f47e54a 100644 --- a/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs +++ b/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs @@ -1264,7 +1264,7 @@ public static IEnumerable SerializableObjects() yield return new object[] { point, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAgAAAAEAAAACAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAgAAAAEAAAACAAAACw==", TargetFrameworkMoniker.netfx461) } }; // Collections - yield return new object[] { new System.Collections.BitArray(5, true), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQml0QXJyYXkDAAAAB21fYXJyYXkIbV9sZW5ndGgIX3ZlcnNpb24HAAAICAgJAgAAAAUAAAAAAAAADwIAAAABAAAACP////8L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQml0QXJyYXkDAAAAB21fYXJyYXkIbV9sZW5ndGgIX3ZlcnNpb24HAAAICAgJAgAAAAUAAAAAAAAADwIAAAABAAAACP////8L", TargetFrameworkMoniker.netfx461) } }; + yield return new object[] { new System.Collections.BitArray(5, true), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQml0QXJyYXkDAAAAB21fYXJyYXkIbV9sZW5ndGgIX3ZlcnNpb24HAAAICAgJAgAAAAUAAAAAAAAADwIAAAABAAAACB8AAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQml0QXJyYXkDAAAAB21fYXJyYXkIbV9sZW5ndGgIX3ZlcnNpb24HAAAICAgJAgAAAAUAAAAAAAAADwIAAAABAAAACP////8L", TargetFrameworkMoniker.netfx461) } }; yield return new object[] { new System.Collections.ArrayList(Enumerable.Range(1, 40).ToList()), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAKAAAAAEAAAAQAgAAACgAAAAICAEAAAAICAIAAAAICAMAAAAICAQAAAAICAUAAAAICAYAAAAICAcAAAAICAgAAAAICAkAAAAICAoAAAAICAsAAAAICAwAAAAICA0AAAAICA4AAAAICA8AAAAICBAAAAAICBEAAAAICBIAAAAICBMAAAAICBQAAAAICBUAAAAICBYAAAAICBcAAAAICBgAAAAICBkAAAAICBoAAAAICBsAAAAICBwAAAAICB0AAAAICB4AAAAICB8AAAAICCAAAAAICCEAAAAICCIAAAAICCMAAAAICCQAAAAICCUAAAAICCYAAAAICCcAAAAICCgAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAKAAAAAEAAAAQAgAAACgAAAAICAEAAAAICAIAAAAICAMAAAAICAQAAAAICAUAAAAICAYAAAAICAcAAAAICAgAAAAICAkAAAAICAoAAAAICAsAAAAICAwAAAAICA0AAAAICA4AAAAICA8AAAAICBAAAAAICBEAAAAICBIAAAAICBMAAAAICBQAAAAICBUAAAAICBYAAAAICBcAAAAICBgAAAAICBkAAAAICBoAAAAICBsAAAAICBwAAAAICB0AAAAICB4AAAAICB8AAAAICCAAAAAICCEAAAAICCIAAAAICCMAAAAICCQAAAAICCUAAAAICCYAAAAICCcAAAAICCgAAAAL", TargetFrameworkMoniker.netfx461) } }; yield return new object[] { new System.Collections.ArrayList(10), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAAAAAAAAAAAQAgAAAAoAAAANCgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAAAAAAAAAAAQAgAAAAoAAAANCgs=", TargetFrameworkMoniker.netfx461) } }; yield return new object[] { new System.Collections.Comparer(new CultureInfo("")), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIBAAAAC0NvbXBhcmVJbmZvAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwkCAAAABAIAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8DAAAABm1fbmFtZQ1tX1NvcnRWZXJzaW9uB2N1bHR1cmUBAwAgU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24IBgMAAAAACn8AAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIBAAAAC0NvbXBhcmVJbmZvAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwkCAAAABAIAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8EAAAABm1fbmFtZQl3aW4zMkxDSUQHY3VsdHVyZQ1tX1NvcnRWZXJzaW9uAQAAAwgIIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uBgMAAAAAAAAAAH8AAAAKCw==", TargetFrameworkMoniker.netfx461) } }; -- GitLab