2009-04-27 1 views
19

В an answer его собственным controversial question, Mash проиллюстрировал, что для чтения и записи непосредственно в байты любого экземпляра объекта .NET вам не нужно «небезопасное» ключевое слово. Вы можете объявить следующие типы:Почему этот код работает без ключевого слова 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; 
    } 

И тогда вы можете делать что-то вроде изменения неизменяемой строки. Следующий печатает код «бар» на моей машине:

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#) ключевое слово unsafe было необходимо для выполнения подобных действий. Почему здесь не нужно? Означает ли это, что чистый управляемый «безопасный» код не совсем безопасен вообще?

+0

Спасибо за изменение способа задать тот же вопрос. Предыдущая нить была переполнена. – Mash

+0

@Mash: проблем нет. Надеемся, что это направит еще более позитивное внимание на ваш первоначальный вопрос. –

+0

@wcoenen: Это не важно, действительно, даже если бы я думал об этом - мой вопрос - это контент сообщества, и я ничего не зарабатываю от него. Поэтому важно только положительное обсуждение. И кажется, что ваш вопрос выглядит лучше :) – Mash

ответ

12

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


Я просто проверял без флага «Full Trust», и среда выполнения отвергает его:

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

И, чтобы иметь этот флаг, вам уже нужно высокое доверие, поэтому вы можете уже делать более неприятные вещи. Строки - это немного другой случай, потому что они не являются нормальными объектами .NET, но есть и другие примеры способов их изменения. Однако подход «union» является интересным. Для другого хакерского способа (с достаточным доверием):

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 
+0

@Marc: Не могли бы вы подробнее рассказать о других методах мутирующих строк, которые вы имеете в виду, пожалуйста? – Brann

+0

Этот код работает нормально без опасного флага. Но сначала требуется полное доверие и использование CAS для установки разрешений, не помогающих (отрицая похожие вещи). Не могли бы вы привести пример, который изменяет содержимое строки и не использует небезопасные блоки? – Mash

+0

Отредактировано, является ли это небезопасным флагом или Full Trust - я изменил разные вещи, поэтому я, возможно, потерял трек ... Re "изменяет строковое содержимое" - не от верхней части головы. Very grotty; -p –

0

Вы по-прежнему отказываетесь от «управляемого» бит. Есть основополагающее предположение, что если вы можете это сделать, тогда вы знаете, что делаете.

5

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

Причина, что пример кода не требует маркировки с unsafe ключевого слова является то, что он не содержит указатели (см ниже цитаты, почему это считается небезопасным). Вы совершенно правы: «безопасный» лучше назвать «дружественным во времени». Для получения дополнительной информации по этой теме я отсылаю вас к Дону Box и Крис Sells Essential .NET

Цитирует MSDN,

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

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

+0

+1 А, это имеет смысл. Это разъясняет, что означает «безопасный». –

+0

Этот код действительно позволяет выйти из границ объекта и изменить любую часть доступной для процесса памяти. Вы можете восстановить блоки синхронизации и ввести дескриптор любых объектов, перейдите в данные GC. Что на самом деле небезопасно дает больше? – Mash

+0

Вот о чем мы говорим. Этот код не имеет признаков того, что CLR не может проверить его безопасность (на самом деле это невозможно). Каждый объект в .NET внутренне использует небезопасный код, но это не приводит к возможности создавать код, объявленный как безопасный, который может получать доступ и изменять данные как небезопасные. – Mash