这段代码有什么不安全的地方?

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 是否管理此代码?此代码可能存在哪些问题?


除了其他人已经说过的,这仍然是100%托管代码。只是它不可验证的内存正确性,工具peverify可以告诉你。 - John
5个回答

6

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

你可以轻松地创建类似于c++的内存泄漏,没有边界检查以及其他问题...

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

在C#中使用不安全代码


6

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


谢谢您的回答!我认为这个解释就是我一直在寻找的。现在对我来说似乎很明显,但直到现在我才看到它。 - vldmrrdjcc
1
Peverify在conv.u上已经失败了,这意味着它拒绝将其视为安全的重新解释加载地址为整数。 - John

5

“不安全”并不意味着危险,但在不安全的代码中有一件事很重要:它是“不可验证的”。这可能意味着许多问题,例如不检查数组边界。在您的简单示例中,并没有太多危险或可怕的东西。它非常直截了当。

因为它可以绕过.NET Framework中的大部分安全机制,所以它也可能是不安全的;这就是为什么不安全的代码需要完全信任的原因。

不安全并不等同于非托管。不安全只是意味着它可以操作指针。


3

这是一篇非常好的文章,我认为这正是我在寻找的。谢谢!只有一个问题:CLR如何知道某些IL代码是不安全的?它是否查看声明的类型,如果看到指针类型,就会决定该代码是不安全的? - vldmrrdjcc

0

默认情况下,微软的C#和Visual Basic.NET编译器会生成“安全”的代码。安全代码是可以被验证为安全的代码。然而,使用C#的不安全关键字或者使用其他语言(例如带托管扩展的C++或者IL汇编语言),你可以生成无法被验证为安全的代码。也就是说,这段代码可能实际上是安全的,但是验证无法证明它。

管理员可以选择关闭验证(使用“.NET Management”微软管理控制台快照)。关闭验证后,JIT编译器将把不可验证的IL编译成本地CPU指令;但是,管理员需要对代码的行为承担全部责任。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接