2010-12-23 17 views
5

考慮下面的代碼:如果更改像這樣的字符串的內容會導致異常?

using System; 
using System.Runtime.InteropServices; 

namespace Demo 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      const string test = "ABCDEF"; // Strings are immutable, right? 
      char[] chars = new StringToChar{str=test}.chr; 
      chars[0] = 'X'; 

      // On an x32 release or debug build or on an x64 debug build, 
      // the following prints "XBCDEF". 
      // On an x64 release build, it prints "ABXDEF". 
      // In both cases, we have changed the contents of 'test' without using 
      // any 'unsafe' code... 

      Console.WriteLine(test); 
     } 
    } 

    [StructLayout(LayoutKind.Explicit)] 
    public struct StringToChar 
    { 
     [FieldOffset(0)] 
     public string str; 
     [FieldOffset(0)] 
     public char[] chr; 
    } 
} 

通過運行該代碼,我們可以改變一個字符串的內容沒有異常發生的歷史。我們不必宣佈任何不安全的代碼就可以這樣做。這段代碼顯然非常狡猾!

我的問題是這樣的:你認爲上面的代碼應該拋出異常嗎?

[EDIT1:請注意,其他人已經嘗試這對我來說,有的人得到不同的結果 - 這是不是太suprising鑑於我在做什麼的nastyness ...;)]

[ EDIT2:請注意,我使用Visual Studio 2010的Windows 7旗艦版64位]

[EDIT3:所做的測試字符串常量,這只是爲了更狡猾]

+2

重複[我已經問過的問題](http://stackoverflow.com/questions/792735/why-does-this-code-work-without-the-unsafe-keyword):-) – 2010-12-23 14:43:47

+0

非常有趣!看起來這是一個衆所周知的問題。 – 2010-12-23 14:50:29

回答

3

我的投票對製作FieldOffset不安全! 。

5

clr/src/vm/class.cpp,MethodTableBuilder :: HandleExplicitLayout的SSCLI20源代碼可以提供一些見解。這條評論描述了規則(爲便於閱讀而編輯):

// go through each field and look for invalid layout 
// (note that we are more permissive than what Ecma allows. We only disallow 
// the minimum set necessary to close security holes.) 
// 
// This is what we implement: 
// 
// 1. Verify that every OREF is on a valid alignment 
// 2. Verify that OREFs only overlap with other OREFs. 
// 3. If an OREF does overlap with another OREF, the class is marked unverifiable. 
// 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()). 

規則1確保參考分配保持原子狀態。規則2說明了爲什麼你可以做你所做的事情,任何對象類型的引用都可能重疊。不允許與值類型值重疊,這會使垃圾收集器陷入困境。規則3規定了後果,它只有使使該類型不可驗證。

否則,它不是唯一的方法來擰一個字符串,而不是不安全的關鍵字。只需捏住一個踩住字符串的函數即可。它獲取一個指向GC堆或裝入堆(實際字符串)的字符串內容的指針,不會創建副本。這是無法驗證的代碼,並且在沙箱中運行時也是無法利用的。

駕車回家:C#不安全關鍵字與CLR認爲可以驗證的內容完全無關,因此實際上是安全代碼。它處理公然的情況,使用指針或自定義值類型(固定)。這是否是C#語言規範中的泄漏是值得商榷的。 Pinvoke是更明顯的邊緣情況。拼命操作系統功能是非常安全的。捏造一些第三方C庫不是。

但是我不得不同意@fej,[FieldOffset]應該得到了「你確定」的待遇。太糟糕了,沒有語法。無可否認,我還沒有想出爲什麼這實際上需要影響管理佈局。這會使得更有意義,這個屬性只適用於編組佈局。奇怪的是,在早期有人拿着他的袖子,也許。

相關問題