编译C#不安全代码

4

我有一个小的C#类,其中包含几个不安全的方法。有没有一种方法可以在C#源代码中(通过#pragma或其他方式)仅针对类的源文件上下文声明"/unsafe"选项?我不想为这样一个小类创建一个单独的程序集,但我也不想让当前程序集中的其他部分启用不安全代码。


4
这不是它的工作方式。使用/unsafe选项只能抑制显式使用“unsafe”关键字的类/方法的编译时错误。它不会以任何方式使未声明为不安全的代码变得不安全。 - Hans Passant
那么,像@StriplingWarrior所建议的那样,在生成的汇编代码中是否有特殊标志呢? - avo
2个回答

7
不,目前这是不可能的,因为整个程序集都会受到包含不安全代码的影响。
通过在程序集中包含不安全代码,您告诉CLR该程序集可能执行某些不安全操作,这将改变运行时加载程序集的方式。最大的变化是CLR不会尝试验证您的不安全代码,并且除非拥有完全信任(例如,您无法作为普通用户通过单击一次来加载不安全程序集),否则它也将拒绝加载您的程序集。
从技术角度来看,当您使用/unsafe选项时,它会导致编译器将以下模块级属性的IL等效项发出到您的程序集中:
[assembly:SecurityPermission(SkipVerification = true)]
[assembly:UnverifiableCode]

您最好的选择是,正如您所说,尽可能将不安全的代码隔离到自己独立的程序集中。由于一个不安全的类而污染整个程序集充满安全代码的事实,比在其中只有一个类的程序集中具有更少的代码异味。

我的理解是,unsafe 是针对每个方法而非程序集的。它也没有被声明(据我所知)。当不可验证的 IL 被放入方法中时,该方法就变得不安全了。 - usr
在C#中,@usr到不安全代码是按代码块进行的,编译器允许您在不安全代码块中执行通常非法的操作。对于运行时来说,不安全代码出现在标记为包含不安全代码的程序集中。尽管安全代码仍然是安全的,但无法告诉运行时“这个程序集的一半是安全的,另一半不是”。例如,即使您从未调用不安全块,整个程序集也需要完全信任才能加载。 - Michael Edenfield
你确定程序集已经标记了吗?这就是我在质疑的。我认为二进制文件中甚至连方法都没有被标记。 - usr
@usr 我的回答可能过于简单了,我会进行修正。 - Michael Edenfield
在C#中,你不仅可以将代码块标记为“unsafe”,还可以将整个“class”标记为“unsafe”。但这可能等同于将该类中的所有“blocks”都标记为“unsafe”。 - Jeppe Stig Nielsen

5
C#有一个"unsafe"关键字,你需要在不安全的代码周围使用它,以避免人们意外地使用不安全的代码。这是一种很好的方法:如果有人能在文件中引入"unsafe"关键字,他们同样可以添加或删除"pragma"标记之类的东西。
"/unsafe"编译器标签告诉编译器,你允许人们在这个程序集中使用"unsafe"关键字,并且你认识到所生成的程序集将被标记为"unsafe",这可能会防止它在不完全信任的环境中运行。没有办法让编译器仅将单个类标记为不安全:人们要么信任你的程序集,要么不信任。

你需要使用 /unsafe 编译器开关来编译包含 unsafe 关键字的代码。 - Michael Edenfield
这很有道理,尽管我对Interop代码(包括WinAPI和COM)被认为比不安全的代码更安全感到惊讶,考虑到Interop不需要“/unsafe”选项。 - avo
Interop 可能是“安全的”,因为它已经经过手工验证。编写汇编代码的开发人员不允许超出 MS 明确允许的范围(这也是为什么“Marshal”类可以“安全地”执行不安全操作的原因)。 - Michael Edenfield
@MichaelEdenfield,我想说,仅使用恶意的IntPtr参数调用RtlZeroMemory可能会造成比我无辜的指针操作更多的损害,而我必须使用“/unsafe”才能进行操作。 - avo

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