1.4.2 Unsafe Code 不安全代码
通常情况下,微软的C#编译器产生的都是安全代码。“安全代码”就是经过验证的安全的代码。然而,微软C#编译器也允许开发者编写不安全的代码。不安全代码可以直接在内存地址上工作,并且可以操作这些地址上的字节(bytes)。这是一个非常强大的功能,在你要与非托管代码交互操作,或者想提高一个对时间要求比较高的算法性能时,这是非常有用的。
但是,使用不安全代码有个非常很大的风险:不安全代码会破坏数据结构,甚至可以利用它打开安全漏洞。因为这个原因,C#编译器要求不安全代码含有用unsafe关键字标记。此外,编译器还需要你选择/unsafe来编译源代码。
当JIT编译器想要编译一个不安全方法,它会先检查程序集里的方法是设置了System.Security.Permissions.SecurityPermission中的System.Security.Permissions.SecurityPermissionFlag 的SkipVerification 标志。如果设置了这个标志,JIT编译器会编译不安全代码并允许它执行。CLR会相信这段代码并希望直接地址和位操作不会有什么损伤。如果没有设置,JIT编译器会抛出一个System.InvalidProgramException 或System.Security.VerificationException异常,来阻止方法的执行。实际上,整个应用程序会在这点终止,但至少不会有什么伤害。
Note:默认情况下,从本地机器或者通过网络工作分享的程序集会完全信任,这意味着它们可以做任何事情,包括执行不安全代码。但是默认情况下,从通过因特网执行的程序集不能执行不安全代码。如果它包含不安全代码,就会抛出前面提到的异常。一个管理员/最终用户能够改变这种默认设置;但是,管理员对这段代码的行为负全部责任。
微软提供了一个叫做PEVerify.exe的工具,它会监测程序集里所有的方法,并提示你哪些方法中含有不安全代码。这也让你知道通过企业内部网(Intranet)或因特网执行你的程序可能会出现哪些错误。
你应该知道,验证需要访问任何独立程序集中包含的元数据。所以当你使用PEVerify来检查程序集的时候,你必须能够找到并加载所有程序集的引用。由于PEVerify 是使用CLR来定位程序集的,所以当执行这个程序集的时候,我们会使用相同的binding和探测规则来将程序集定位。我会在第二章和第三章来介绍这些binding和probing rules。