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 是否管理此代码?上面的代码会出现什么问题?

4

5 回答 5

6

它被称为不安全,部分原因是它不受管理。

您可以轻松创建 c++ 风格的内存泄漏,没有边界检查,以及其他问题......

一篇关于不安全代码的好文章,也列出了一些风险:

在 C# 中使用不安全代码

于 2011-06-24T18:01:43.383 回答
6

使这段代码不安全的原因是使用了“ldind.i4”语句。这会从内存地址加载一个带符号的 4 字节整数。可以给出任何内存地址,允许您从当前进程中的任何内存地址读取。这被认为是不安全且无法验证的。例如,您可以使用它来查看其他应用程序域,这是不允许的。

于 2011-07-27T15:03:42.237 回答
5

不安全可能并不意味着危险,但在不安全的代码中有一件很重要的事情:它是不可验证的。这可能意味着几件事,例如不检查数组的边界。在您的简单示例中。它没有那么危险或可怕。这很简单。

In 可能是不安全的,因为它还绕过了 .NET Framework 中的大多数安全机制;这就是为什么不安全的代码无论如何都需要完全信任的原因。

不安全!= 非托管。不安全只是意味着它可以操纵指针。

于 2011-06-24T18:08:38.427 回答
3

通常,unsafe关键字允许您直接访问内存,因此绕过 CLR 的所有验证和安全检查。

unsafe这里有一篇关于代码 使用和影响的好文章:http: //blogs.msdn.com/b/sebby1234/archive/2006/04/05/565090.aspx

于 2011-06-24T18:08:20.287 回答
0

默认情况下,Microsoft 的 C# 和 Visual Basic.NET 编译器生成“安全”代码。安全代码是可验证安全的代码。但是,使用 C# 的 unsafe 关键字或使用其他语言(例如带有托管扩展的 C++ 或 IL 汇编语言),您可以生成无法验证安全的代码。也就是说,代码实际上可能是安全的,但验证无法证明这一点。

管理员可以选择关闭验证(使用“.NET Management”Microsoft 管理控制台管理单元)。关闭验证后,JIT 编译器会将无法验证的 IL 编译为原生 CPU 指令;但是,管理员对代码的行为负有全部责任。

于 2012-02-23T09:39:00.313 回答