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" />