Skip to content

Commit ffcdaeb

Browse files
authored
Don't mutating the ScopeId on static readonly IPAddress fields (#115456)
The Address field was made readonly in dotnet/corefx#33531. Somehow ScopeId, the only other mutatable property, was missed. I did not see discussion of this in that PR or the related issue. An example program that illistrates the problem: ```csharp Console.WriteLine(IPAddress.IPv6Loopback); IPAddress.IPv6Loopback.ScopeId = 1; Console.WriteLine(IPAddress.IPv6Loopback); ``` This prints: ```txt ::1 ::1%1 ``` I think the right behavior is to throw when setting the ScopeId (this pr). Contributes to #27870
1 parent fb7050d commit ffcdaeb

File tree

2 files changed

+15
-3
lines changed

2 files changed

+15
-3
lines changed

src/libraries/System.Net.Primitives/src/System/Net/IPAddress.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ public class IPAddress : ISpanFormattable, ISpanParsable<IPAddress>, IUtf8SpanFo
2828

2929
internal const uint LoopbackMaskHostOrder = 0xFF000000;
3030

31-
public static readonly IPAddress IPv6Any = new IPAddress((ReadOnlySpan<byte>)[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0);
32-
public static readonly IPAddress IPv6Loopback = new IPAddress((ReadOnlySpan<byte>)[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 0);
31+
public static readonly IPAddress IPv6Any = new ReadOnlyIPAddress([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0);
32+
public static readonly IPAddress IPv6Loopback = new ReadOnlyIPAddress([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 0);
3333
public static readonly IPAddress IPv6None = IPv6Any;
3434

35-
private static readonly IPAddress s_loopbackMappedToIPv6 = new IPAddress((ReadOnlySpan<byte>)[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1], 0);
35+
private static readonly IPAddress s_loopbackMappedToIPv6 = new ReadOnlyIPAddress([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1], 0);
3636

3737
/// <summary>
3838
/// For IPv4 addresses, this field stores the Address.
@@ -438,6 +438,11 @@ public long ScopeId
438438
ThrowSocketOperationNotSupported();
439439
}
440440

441+
if (this is ReadOnlyIPAddress)
442+
{
443+
ThrowSocketOperationNotSupported();
444+
}
445+
441446
// Consider: Since scope is only valid for link-local and site-local
442447
// addresses we could implement some more robust checking here
443448
ArgumentOutOfRangeException.ThrowIfNegative(value);
@@ -772,6 +777,9 @@ private sealed class ReadOnlyIPAddress : IPAddress
772777
{
773778
public ReadOnlyIPAddress(ReadOnlySpan<byte> newAddress) : base(newAddress)
774779
{ }
780+
781+
public ReadOnlyIPAddress(ReadOnlySpan<byte> address, long scopeid) : base(address, scopeid)
782+
{ }
775783
}
776784
}
777785
}

src/libraries/System.Net.Primitives/tests/FunctionalTests/IPAddressTest.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,10 @@ public static void Address_ReadOnlyStatics_Set_Failure()
346346
Assert.Throws<SocketException>(() => IPAddress.Broadcast.Address = MaxAddress - 1);
347347
Assert.Throws<SocketException>(() => IPAddress.Loopback.Address = MaxAddress - 1);
348348
Assert.Throws<SocketException>(() => IPAddress.None.Address = MaxAddress - 1);
349+
350+
Assert.Throws<SocketException>(() => IPAddress.IPv6Any.ScopeId = 1);
351+
Assert.Throws<SocketException>(() => IPAddress.IPv6Loopback.ScopeId = 1);
352+
Assert.Throws<SocketException>(() => IPAddress.IPv6None.ScopeId = 1);
349353
}
350354
#pragma warning restore 618
351355
}

0 commit comments

Comments
 (0)