From 8a4934feb182a4974ecbf805e24cd9870e85fd28 Mon Sep 17 00:00:00 2001
From: Ahson Khan <ahkha@microsoft.com>
Date: Fri, 17 Nov 2017 16:13:01 -0800
Subject: [PATCH] Adding null check for implicit cast from array to Span.
 (#25257)

* Adding null check for implicit cast from array to Span.

* Addressing PR feedback - adding check for ArraySegment
---
 src/System.Memory/src/System/ReadOnlySpan.cs  |  5 ++--
 src/System.Memory/src/System/Span.cs          |  5 ++--
 .../tests/ReadOnlySpan/ImplicitConversion.cs  | 27 +++++++++++++++++++
 .../tests/Span/ImplicitConversion.cs          | 27 +++++++++++++++++++
 .../tests/System.Memory.Tests.csproj          |  2 ++
 5 files changed, 62 insertions(+), 4 deletions(-)
 create mode 100644 src/System.Memory/tests/ReadOnlySpan/ImplicitConversion.cs
 create mode 100644 src/System.Memory/tests/Span/ImplicitConversion.cs

diff --git a/src/System.Memory/src/System/ReadOnlySpan.cs b/src/System.Memory/src/System/ReadOnlySpan.cs
index 63db2285169d..783275dfeb80 100644
--- a/src/System.Memory/src/System/ReadOnlySpan.cs
+++ b/src/System.Memory/src/System/ReadOnlySpan.cs
@@ -242,12 +242,13 @@ public override int GetHashCode()
         /// <summary>
         /// Defines an implicit conversion of an array to a <see cref="ReadOnlySpan{T}"/>
         /// </summary>
-        public static implicit operator ReadOnlySpan<T>(T[] array) => new ReadOnlySpan<T>(array);
+        public static implicit operator ReadOnlySpan<T>(T[] array) => array != null ? new ReadOnlySpan<T>(array) : default;
 
         /// <summary>
         /// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="ReadOnlySpan{T}"/>
         /// </summary>
-        public static implicit operator ReadOnlySpan<T>(ArraySegment<T> arraySegment) => new ReadOnlySpan<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
+        public static implicit operator ReadOnlySpan<T>(ArraySegment<T> arraySegment)
+            => arraySegment.Array != null ? new ReadOnlySpan<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count) : default;
 
         /// <summary>
         /// Forms a slice out of the given read-only span, beginning at 'start'.
diff --git a/src/System.Memory/src/System/Span.cs b/src/System.Memory/src/System/Span.cs
index 71df73622edf..3f719a07407d 100644
--- a/src/System.Memory/src/System/Span.cs
+++ b/src/System.Memory/src/System/Span.cs
@@ -348,12 +348,13 @@ public override int GetHashCode()
         /// <summary>
         /// Defines an implicit conversion of an array to a <see cref="Span{T}"/>
         /// </summary>
-        public static implicit operator Span<T>(T[] array) => new Span<T>(array);
+        public static implicit operator Span<T>(T[] array) => array != null ? new Span<T>(array) : default;
 
         /// <summary>
         /// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="Span{T}"/>
         /// </summary>
-        public static implicit operator Span<T>(ArraySegment<T> arraySegment) => new Span<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
+        public static implicit operator Span<T>(ArraySegment<T> arraySegment)
+            => arraySegment.Array != null ? new Span<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count) : default;
 
         /// <summary>
         /// Defines an implicit conversion of a <see cref="Span{T}"/> to a <see cref="ReadOnlySpan{T}"/>
diff --git a/src/System.Memory/tests/ReadOnlySpan/ImplicitConversion.cs b/src/System.Memory/tests/ReadOnlySpan/ImplicitConversion.cs
new file mode 100644
index 000000000000..ba579c99e6a1
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/ImplicitConversion.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+    public static partial class ReadOnlySpanTests
+    {
+        [Fact]
+        public static void NullImplicitCast()
+        {
+            int[] dst = null;
+            ReadOnlySpan<int> srcSpan = dst;
+            Assert.True(ReadOnlySpan<int>.Empty == srcSpan);
+        }
+
+        [Fact]
+        public static void ArraySegmentDefaultImplicitCast()
+        {
+            ArraySegment<int> dst = default;
+            ReadOnlySpan<int> srcSpan = dst;
+            Assert.True(ReadOnlySpan<int>.Empty == srcSpan);
+        }
+    }
+}
diff --git a/src/System.Memory/tests/Span/ImplicitConversion.cs b/src/System.Memory/tests/Span/ImplicitConversion.cs
new file mode 100644
index 000000000000..4d10d55d522e
--- /dev/null
+++ b/src/System.Memory/tests/Span/ImplicitConversion.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+    public static partial class SpanTests
+    {
+        [Fact]
+        public static void NullImplicitCast()
+        {
+            int[] dst = null;
+            Span<int> srcSpan = dst;
+            Assert.True(Span<int>.Empty == srcSpan);
+        }
+
+        [Fact]
+        public static void ArraySegmentDefaultImplicitCast()
+        {
+            ArraySegment<int> dst = default;
+            Span<int> srcSpan = dst;
+            Assert.True(Span<int>.Empty == srcSpan);
+        }
+    }
+}
diff --git a/src/System.Memory/tests/System.Memory.Tests.csproj b/src/System.Memory/tests/System.Memory.Tests.csproj
index b2f7fa656ef3..e6acb8182de0 100644
--- a/src/System.Memory/tests/System.Memory.Tests.csproj
+++ b/src/System.Memory/tests/System.Memory.Tests.csproj
@@ -29,6 +29,7 @@
     <Compile Include="Span\GcReporting.cs" />
     <Compile Include="Span\GetEnumerator.cs" />
     <Compile Include="Span\GetHashCode.cs" />
+    <Compile Include="Span\ImplicitConversion.cs" />
     <Compile Include="Span\IndexOf.T.cs" />
     <Compile Include="Span\IndexOf.byte.cs" />
     <Compile Include="Span\IndexOf.char.cs" />
@@ -58,6 +59,7 @@
     <Compile Include="ReadOnlySpan\Equality.cs" />
     <Compile Include="ReadOnlySpan\GetEnumerator.cs" />
     <Compile Include="ReadOnlySpan\GetHashCode.cs" />
+    <Compile Include="ReadOnlySpan\ImplicitConversion.cs" />
     <Compile Include="ReadOnlySpan\IndexOf.T.cs" />
     <Compile Include="ReadOnlySpan\IndexOf.byte.cs" />
     <Compile Include="ReadOnlySpan\IndexOf.char.cs" />