2011-06-24 48 views
8

我正在學習CLR中的託管代碼和非託管代碼。 所以我寫了與C風格的指針這個例子在C#:這段代碼中有什麼不安全的東西?

unsafe static void Main(string[] args) 
{ 
    int x; 
    int* y; 
    y = &x; 
    *y = 50; 
    Console.WriteLine(*y); 
    Console.WriteLine(((int)y).ToString()); 
} 

所以我想知道什麼是真正的IL代碼,我從上面的代碼有不安全?

.assembly extern mscorlib 
{} 
.assembly UnsafePointers 
{} 
.module UnsafePointers.exe 
.class private auto ansi beforefieldinit UnsafePointers.Program 
extends [mscorlib]System.Object 
{ 
    .method private hidebysig static void Main(string[] args) cil managed 
    { 
     .entrypoint 
     // Code size  34 (0x22) 
     .locals init (int32 x, 
     int32* y) 
     IL_0001: ldloca  x 
     IL_0003: conv.u 
     IL_0004: stloc  y 
     IL_0005: ldloc y 
     IL_0006: ldc.i4 50 
     IL_0008: stind.i4 
     IL_0009: ldloc  y 
     IL_000a: ldind.i4 
     IL_000b: call  void [mscorlib]System.Console::WriteLine(int32) 
     IL_0010: nop 
     IL_0011: ldloca  y 
     IL_0012: conv.i4 
     IL_0016: call  instance string [mscorlib]System.Int32::ToString() 
     IL_001b: call  void [mscorlib]System.Console::WriteLine(string) 
     IL_0021: ret 
    } 
}  

CLR是否管理這段代碼?上面的代碼會出現什麼問題?

+0

除了別人已經說過的之外,這仍然是100%託管代碼。只是它不能驗證內存正確,因爲工具驗證可以告訴你。 – John

回答

6

這段代碼不安全的原因是使用'ldind.i4'語句。這將從內存地址加載帶符號的4字節整數。可以給出任何存儲器地址,允許您從當前進程中的任何存儲器地址讀取數據。這被認爲是不安全和不可驗證的。例如,您可以使用它來查看其他應用程序域,這是不允許的。

+0

謝謝你的回答!我認爲這個解釋是我正在尋找的。現在看來對我來說很明顯,但直到現在我纔看到它。 – vldmrrdjcc

+1

Peverify已經在'conv.u'上失敗了,這意味着它拒絕調用它作爲整數重新解析加載的地址是安全的。 – John

6

它被稱爲不安全,部分原因是它不受管理。

您可以輕鬆創建C++風格的內存泄漏,沒有邊界檢查,及其他問題...

不安全的代碼,一個很好的文章,也列出了一些風險:

Using Unsafe Code in C#

+0

它仍然是託管代碼,它只是無法驗證。 – John

3

通常,關鍵字unsafe允許您直接訪問內存,因此可以繞過CLR的所有驗證和安全檢查。

下面是對使用的好文章和unsafe代碼的影響: http://blogs.msdn.com/b/sebby1234/archive/2006/04/05/565090.aspx

+0

這是非常好的文章,我認爲這是我正在尋找的。謝謝!還有一個問題:CLR如何知道某些IL代碼不安全?它是否查看聲明的類型,並且如果它看到,例如指針類型,它會判定代碼是不安全的? – vldmrrdjcc

4

不安全可能並不意味着危險,但有一件事是在不安全的代碼,重要的是:它是無法證實。這可能意味着幾件事情,比如不檢查數組的邊界。在你的簡單例子。沒有那麼危險或可怕。這非常簡單。

In可能是不安全的,因爲它也解決了.NET Framework中的大多數安全機制;這就是爲什麼不安全的代碼無論如何都需要Full Trust。

不安全!=非託管。不安全意味着它可以操縱指針。

0

默認情況下,Microsoft的C#和Visual Basic.NET編譯器會生成「安全」代碼。安全代碼是可驗證安全的代碼。但是,使用C#的不安全關鍵字或使用其他語言(例如帶有託管擴展或IL彙編語言的C++),您可以生成無法驗證安全的代碼。也就是說,代碼實際上可能是安全的,但驗證無法證明它。

管理員可以選擇關閉驗證(使用「.NET管理」Microsoft 管理控制檯管理單元)。驗證關閉後,JIT編譯器會將無法驗證的IL編譯爲本機CPU指令;但是,管理員對代碼的行爲負全部責任。