writing to too small buffer should throw an exception (dotnet/corefx#37661)
authorAdam Sitnik <adam.sitnik@gmail.com>
Wed, 19 Jun 2019 08:06:28 +0000 (10:06 +0200)
committerGitHub <noreply@github.com>
Wed, 19 Jun 2019 08:06:28 +0000 (10:06 +0200)
fixes dotnet/corefx#35231

Commit migrated from https://github.com/dotnet/corefx/commit/721a570b005c53a839947603dcf76f8a3e5fc56a

src/libraries/System.Memory/src/System/Buffers/BuffersExtensions.cs
src/libraries/System.Memory/src/System/ThrowHelper.cs
src/libraries/System.Memory/tests/BuffersExtensions/BuffersExtensionsTests.cs

index a038df9..94ec060 100644 (file)
@@ -110,6 +110,9 @@ namespace System.Buffers
         /// <summary>
         /// Writes contents of <paramref name="value"/> to <paramref name="writer"/>
         /// </summary>
+        /// <exception cref="System.ArgumentOutOfRangeException">
+        /// Thrown when the <paramref name="writer"/> is shorter than the <paramref name="value"/>.
+        /// </exception>
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static void Write<T>(this IBufferWriter<T> writer, ReadOnlySpan<T> value)
         {
@@ -139,6 +142,12 @@ namespace System.Buffers
                 if (input.Length > 0)
                 {
                     destination = writer.GetSpan();
+
+                    if (destination.IsEmpty)
+                    {
+                        ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.writer);
+                    }
+
                     continue;
                 }
 
index a4b606e..98fa8a4 100644 (file)
@@ -120,6 +120,7 @@ namespace System
         array,
         culture,
         manager,
-        count
+        count,
+        writer,
     }
 }
index eefc9c4..445c348 100644 (file)
@@ -29,6 +29,75 @@ namespace System.Buffers.Tests
             Assert.Equal("Hello World!", bufferWriter.ToString());
         }
 
+        [Fact]
+        public void WritingEmptyBufferToSingleSegmentEmptyBufferWriterDoesNothing()
+        {
+            IBufferWriter<byte> bufferWriter = new MultiSegmentArrayBufferWriter<byte>(
+                new byte[][] { Array.Empty<byte>() }
+            );
+
+            bufferWriter.Write(Array.Empty<byte>()); // This is equivalent to: Span<byte>.Empty.CopyTo(Span<byte>.Empty);
+        }
+
+        [Fact]
+        public void WritingEmptyBufferToMultipleSegmentEmptyBufferWriterDoesNothing()
+        {
+            IBufferWriter<byte> bufferWriter = new MultiSegmentArrayBufferWriter<byte>(
+                new byte[][] { Array.Empty<byte>(), Array.Empty<byte>() }
+            );
+
+            bufferWriter.Write(Array.Empty<byte>());
+        }
+
+        [Theory]
+        [InlineData(1, 0)]
+        [InlineData(10, 9)]
+        public void WritingToTooSmallSingleSegmentBufferFailsWithException(int inputSize, int destinationSize)
+        {
+            IBufferWriter<byte> bufferWriter = new MultiSegmentArrayBufferWriter<byte>(
+                new byte[][] { new byte[destinationSize] }
+            );
+
+            Assert.Throws<ArgumentOutOfRangeException>(paramName: "writer", testCode: () => bufferWriter.Write(new byte[inputSize]));
+        }
+
+        [Theory]
+        [InlineData(10, 2, 2)]
+        [InlineData(10, 9, 0)]
+        public void WritingToTooSmallMultiSegmentBufferFailsWithException(int inputSize, int firstSegmentSize, int secondSegmentSize)
+        {
+            IBufferWriter<byte> bufferWriter = new MultiSegmentArrayBufferWriter<byte>(
+                new byte[][] {
+                    new byte[firstSegmentSize],
+                    new byte[secondSegmentSize]
+                }
+            );
+
+            Assert.Throws<ArgumentOutOfRangeException>(
+                paramName: "writer", 
+                testCode: () => bufferWriter.Write(new byte[inputSize]));
+        }
+
+        private class MultiSegmentArrayBufferWriter<T> : IBufferWriter<T>
+        {
+            private readonly T[][] _segments;
+            private int _segmentIndex;
+
+            public MultiSegmentArrayBufferWriter(T[][] segments) => _segments = segments;
+
+            public void Advance(int size)
+            {
+                if (size != _segments[_segmentIndex].Length)
+                    throw new NotSupportedException("By design");
+
+                _segmentIndex++;
+            }
+
+            public Memory<T> GetMemory(int sizeHint = 0) => _segmentIndex < _segments.Length ? _segments[_segmentIndex] : Memory<T>.Empty;
+
+            public Span<T> GetSpan(int sizeHint = 0) => _segmentIndex < _segments.Length ? _segments[_segmentIndex] : Span<T>.Empty;
+        }
+
         private class TestBufferWriterSingleSegment : IBufferWriter<byte>
         {
             private byte[] _buffer = new byte[1000];