簡體   English   中英

為什么這段代碼沒有unsafe關鍵字?

[英]Why does this code work without the unsafe keyword?

回答他自己有爭議的問題時Mash已經說明你不需要“unsafe”關鍵字直接讀寫任何.NET對象實例的字節。 您可以聲明以下類型:

   [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#代碼中) unsafe關鍵字是必要的,以執行此類操作。 為什么這里沒有必要? 這是否意味着純粹的托管“安全”代碼根本不安全?

好吧,這是令人討厭的......使用工會的危險。 這可能有用,但不是一個好主意 - 我想我會將它與反射(你可以做大多數事情)進行比較。 我有興趣看看它是否在受限制的訪問環境中工作 - 如果是這樣,它可能代表一個更大的問題......


我剛剛測試它沒有“完全信任”標志,運行時拒絕它:

無法從程序集“ConsoleApplication4,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null”加載類型“MemoryAccess”,因為對象在偏移0處重疊且程序集必須是可驗證的。

要擁有這面旗幟,你已經需要高度信任 - 所以你已經可以做更多討厭的事了。 字符串是一個稍微不同的情況,因為它們不是正常的.NET對象 - 但是還有其他一些方法可以改變它們 - 但“聯合”方法是一個有趣的方法。 對於另一種hacky方式(有足夠的信任):

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

哎呀,我已經fixed unsafe了。 這是一個更正版本:

示例代碼不需要使用unsafe關鍵字進行標記的原因是它不包含指針 (請參閱下面的引用,了解為什么這被認為是不安全的)。 你是完全正確的:“安全”可能更好地被稱為“運行時友好”。 有關此主題的更多信息,我將向您推薦Don Box和Chris Sells Essential .NET

引用MSDN,

在公共語言運行庫(CLR)中,不安全的代碼稱為無法驗證的代碼。 C#中的不安全代碼不一定是危險的; 這只是CLR無法驗證其安全性的代碼。 因此,如果CLR位於完全受信任的程序集中,則它只會執行不安全的代碼。 如果使用不安全的代碼,則您有責任確保代碼不會引入安全風險或指針錯誤。

固定和不安全之間的區別在於固定阻止CLR在內存中移動東西,因此運行時之外的東西可以安全地訪問它們,而不安全則恰恰相反的問題:CLR可以保證正確的解決方案dotnet引用,它不能為指針這樣做。 你可能還記得各種關於引用如何不是指針的微軟,這就是為什么它們會對一個微妙的區別做出如此大驚小怪的原因。

你仍然選擇退出'托管'位。 有一個潛在的假設,如果你能做到那么你知道你在做什么。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM