なぜこのコードは unsafe キーワードなしで機能するのでしょうか?
質問
で 答え 自分のものに 物議を醸す質問, マッシュ .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;
}
そして、「不変」文字列を変更するなどの操作を行うことができます。次のコードは、私のマシン上で「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);
をトリガーすることもできます アクセス違反例外 同じ手法でオブジェクト参照を破壊することによって。
質問:(純粋なマネージド C# コードでは) 危険な このようなことを行うにはキーワードが必要でした。なぜここでは必要ないのでしょうか? これは、純粋にマネージドされた「安全な」コードは実際にはまったく安全ではないことを意味するのでしょうか?
解決
わかりました、それは厄介です...労働組合を使用する危険性。それは機能するかもしれませんが、あまり良いアイデアではありません。私はそれをリフレクション(ほとんどのことができる)と比較すると思います。これが制限されたアクセス環境で機能するかどうかを確認してみたいと思います。もし機能する場合は、より大きな問題が発生する可能性があります...
「完全信頼」フラグなしでテストしたところ、ランタイムがそれを拒否しました。
アセンブリ 'consoleApplication4、バージョン= 1.0.0.0、culture = neutral、publickeytoken = null'からタイプ「メモリアクセス」をロードできませんでした。
そして、このフラグを持つには、すでに高い信頼が必要です。そのため、すでにさらに厄介なことが実行できるようになります。文字列は通常の .NET オブジェクトではないため、少し異なります。ただし、文字列を変更する方法の例は他にもあります。ただし、「ユニオン」アプローチは興味深いものです。別のハッキングな方法 (十分な信頼があれば):
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
キーワードは以下が含まれていないことです ポインタ (これが安全でないとみなされる理由については、以下の引用を参照してください)。あなたはまったく正しいです:「安全」は「実行時に優しい」と言い換えた方がよいかもしれません。このトピックの詳細については、Don Box と Chris Sells を参照してください。 必須の.NET
MSDN を引用すると、
共通言語ランタイム(CLR)では、安全でないコードが検証不可能なコードと呼ばれます。C#の安全でないコードは必ずしも危険ではありません。CLRによって安全性を検証できないのは、単なるコードです。したがって、CLRは、完全に信頼できるアセンブリにある場合にのみ、安全でないコードを実行します。安全でないコードを使用する場合、コードがセキュリティリスクやポインターエラーを導入しないことを確認するのはお客様の責任です。
fix と unsafe の違いは、fixed では CLR がメモリ内でオブジェクトを移動するのを停止し、ランタイム外のものが安全にアクセスできるようにするのに対し、unsafe はまったく逆の問題です。CLR は、ドットネット参照の正しい解決を保証できますが、ポインターの場合は保証できません。さまざまな Microsoft 関係者が、参照はポインタではないことについて議論していたことを覚えているかもしれません。これが、彼らが微妙な区別についてこれほど大騒ぎする理由です。
まだ「管理対象」ビットをオプトアウトしています。それができれば、自分が何をしているのかわかっているという前提が根底にあります。