我正在学习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 :(得分:6)
它被称为不安全,部分原因是它不受管理。
您可以轻松创建c ++样式内存泄漏,没有边界检查和其他问题......
一篇关于不安全代码的好文章,也列出了一些风险:
答案 1 :(得分:6)
使这段代码不安全的原因是使用'ldind.i4'语句。这将从内存地址加载一个带符号的4字节整数。可以给出任何存储器地址,允许您从当前进程中的任何存储器地址读取。这被认为是不安全和无法验证的。例如,您可以使用它来查看其他appdomains,这是不允许的。
答案 2 :(得分:4)
不安全可能并不意味着危险,但有一件事在不安全的代码中很重要:它是无法验证的。这可能意味着几件事,例如不检查数组的边界。在你的简单例子中。关于它没有那么多危险或可怕。这很直接。
In可能不安全,因为它也可以解决.NET Framework中的大多数安全机制;这就是为什么不安全的代码无论如何都要求完全信任。
不安全!=不受管理。不安全只意味着它可以操纵指针。
答案 3 :(得分:3)
通常,unsafe
关键字允许您直接访问内存,因此会绕过CLR的所有验证和安全检查。
这是一篇关于unsafe
代码的使用和影响的好文章:
http://blogs.msdn.com/b/sebby1234/archive/2006/04/05/565090.aspx
答案 4 :(得分:0)
默认情况下,Microsoft的C#和Visual Basic.NET编译器生成“安全”代码。安全代码是可验证的安全代码。但是,使用C#的unsafe关键字或使用其他语言(例如C ++ with Managed Extensions或IL Assembly语言),您可以生成无法安全的代码。也就是说,代码实际上可能是安全的,但验证无法证明它。
管理员可以选择关闭验证(使用“.NET管理”Microsoft 管理控制台管理单元)。关闭验证后,JIT编译器会将无法验证的IL编译为本机CPU指令;但是,管理员对代码的行为负全部责任。