Подтвердить что ты не робот

Почему IPAddress.MapToIPv4() выбрасывает ArgumentOutOfRangeException?

Этот код генерирует исключение ArgumentOutOfRangeException в последней строке

var initAddress = IPAddress.Parse("1.65.128.190");
var ipv6Address = initAddress.MapToIPv6();
Assert.IsTrue(ipv6Address.IsIPv4MappedToIPv6);
var ipv4Address = ipv6Address.MapToIPv4();

Может ли кто-нибудь объяснить, почему MapToIPv6() и MapToIPv4() не совместимы с обеими сторонами?

edit: Исключение происходит от конструктора IPAddress, вызываемого MapToIPv4().

Кроме того, когда первая строка

var initAddress = IPAddress.Parse("1.65.128.90");

больше исключений исключений

edit2: как @Luaan воспроизвел это, я добавил тег [bug-reporting]. Также добавлен [bcl]. Посмотрите, отслеживает ли какой-либо персонал MS эти теги:)

edit3: сообщается в Connect https://connect.microsoft.com/VisualStudio/feedback/details/871964

4b9b3361

Ответ 1

Хорошо, я действительно проверил это, поэтому позвольте мне опубликовать это как ответ.

Класс IPAddress имеет ошибку при отображении адреса на IPv4.

В соответствии с кодом ссылки .NET он делает следующее:

long address = 
  (((m_Numbers[6] & 0x0000FF00) >> 8) | ((m_Numbers[6] & 0x000000FF) << 8)) |
  ((((m_Numbers[7] & 0x0000FF00) >> 8) | ((m_Numbers[7] & 0x000000FF) << 8)) << 16);

Проблема должна быть очевидна для всех, кто выполняет побитовые операции в .NET - все числа int s. Поэтому смещение второго ushort (m_Numbers[7]) даст отрицательное значение, поскольку самый старший бит - 1. Это означает, что все адреса IPv4, заканчивающиеся байтом выше 127, вызовут ошибку при отображении обратно с IPv6.

Простым исправлением будет следующее:

long address = 
 (((m_Numbers[6] & 0x0000FF00) >> 8) | ((m_Numbers[6] & 0x000000FF) << 8)) 
 |
 (
  (uint)(((m_Numbers[7] & 0x0000FF00) >> 8) | ((m_Numbers[7] & 0x000000FF) << 8))
  << 16
 );

Просто, переведя int в uint, прежде чем делать бит-брейк, делает трюк.

Побитовые операции могут быть довольно сложными, если вы учитываете подписанные типы. Я предполагаю, что код был скопирован из библиотеки С++ или чего-то еще, где эта проблема не будет отображаться.