Почему этот код работает без ключевого слова unsafe?

StackOverflow https://stackoverflow.com/questions/792735

  •  16-09-2019
  •  | 
  •  

Вопрос

В ответ к его собственному спорный вопрос, Пюре показал, что вам не нужно ключевое слово "unsafe" для чтения и записи непосредственно в байты любого .Экземпляр СЕТЕВОГО объекта.Вы можете объявить следующие типы:

   [StructLayout(LayoutKind.Explicit)]
   struct MemoryAccess
   {

      [FieldOffset(0)]
      public object Object;

      [FieldOffset(0)]
      public TopBytes Bytes;
   }

   class TopBytes
   {
      public byte b0;
      public byte b1;
      public byte b2;
      public byte b3;
      public byte b4;
      public byte b5;
      public byte b6;
      public byte b7;
      public byte b8;
      public byte b9;
      public byte b10;
      public byte b11;
      public byte b12;
      public byte b13;
      public byte b14;
      public byte b15;
   }

И затем вы можете делать такие вещи, как изменение "неизменяемой" строки.Следующий код выводит "bar" на моем компьютере:

 string foo = "foo";
 MemoryAccess mem = new MemoryAccess();
 mem.Object = foo;
 mem.Bytes.b8 = (byte)'b';
 mem.Bytes.b10 = (byte)'a';
 mem.Bytes.b12 = (byte)'r';
 Console.WriteLine(foo);

Вы также можете вызвать Исключение AccessViolationException путем искажения ссылок на объекты с помощью той же техники.

Вопрос:Я думал, что (в чистом управляемом коде C #) небезопасно ключевое слово было необходимо, чтобы делать подобные вещи.Почему здесь в этом нет необходимости? Означает ли это, что чистый управляемый "безопасный" код на самом деле вообще не безопасен?

Это было полезно?

Решение

Ладно, это отвратительно...опасности использования профсоюза.Это может сработать, но это не очень хорошая идея - думаю, я бы сравнил это с отражением (где вы можете делать большинство вещей).Мне было бы интересно посмотреть, работает ли это в среде с ограниченным доступом - если да, то это может представлять более серьезную проблему...


Я только что протестировал его без флага "Полное доверие", и среда выполнения отклоняет его:

Не удалось загрузить тип 'MemoryAccess' из сборки 'ConsoleApplication4, Версия =1.0.0.0, язык = нейтральный, PublicKeyToken=null', поскольку объекты перекрывается со смещением 0 и сборка должна быть проверяемой.

И чтобы иметь этот флаг, вам уже нужно высокое доверие - так что вы уже можете делать больше неприятных вещей.Строки - это немного другой случай, потому что они не являются обычными .СЕТЕВЫЕ объекты - но есть и другие примеры способов их изменения - хотя подход "объединения" является интересным.Для другого взломанного способа (с достаточным доверием):

string orig = "abc   ", copy = orig;
typeof(string).GetMethod("AppendInPlace",
    BindingFlags.NonPublic | BindingFlags.Instance,
    null, new Type[] { typeof(string), typeof(int) }, null)
    .Invoke(orig, new object[] { "def", 3 });
Console.WriteLine(copy); // note we didn't touch "copy", so we have
                         // mutated the same reference

Другие советы

Упс, я запутался unsafe с fixed.Вот исправленная версия:

Причина в том, что пример кода не требует пометки с помощью unsafe ключевое слово заключается в том, что оно не содержит указатели (смотрите приведенную ниже цитату о том, почему это считается небезопасным).Вы совершенно правы:"безопасный" лучше было бы назвать "дружественным ко времени выполнения".Для получения дополнительной информации по этой теме я отсылаю вас к Дону Боксу и Крису Селлсу Необходимый .NET

Процитировать MSDN,

В среде common language runtime (CLR) небезопасный код упоминается как непроверяемый код.Небезопасный код в C# не обязательно опасен;это просто код, безопасность которого не может быть проверена CLR.Среда CLR будет следовательно, выполнять небезопасный код, только если он находится в полностью доверенной сборке.Если вы используете небезопасный код, вы несете ответственность за то, чтобы убедиться, что ваш код не создает угроз безопасности или ошибок указателя.

Разница между fixed и unsafe заключается в том, что fixed останавливает среду CLR от перемещения объектов в памяти, так что объекты вне времени выполнения могут безопасно обращаться к ним, тогда как unsafe - это как раз противоположная проблема:хотя среда CLR может гарантировать правильное разрешение для ссылки на dotnet, она не может этого сделать для указателя.Возможно, вы помните, что различные компании Microsoft говорили о том, что ссылка - это не указатель, и именно поэтому они поднимают такой шум из-за тонкого различия.

Вы по-прежнему отказываетесь от раздела "управляемый".В основе лежит предположение, что если вы можете это сделать, то вы знаете, что делаете.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top