C#中有趣的类型系统违规(在安全的环境中)
我谈到的类型系统违规 – 是在模仿工会时。
为什么在安全的环境中允许它?
-
它允许您处理值类型,作为不同的值类型 – 正如您将实现的那样:
float f = 2.5f;
int binaryIdenticalInt = *((int *)&f); -
它允许您引用类型为X的对象,因为它是Y类型,即使这些类型之间没有关系。
-
它允许您创建CLR甚至不会加载的类型(如果至少有一个重叠字段是引用类型,并且其中至少有一个是值/指针类型 – CLR将拒绝加载它)。 我希望C#编译器比它允许的内容更加挑剔,而不是CLR。 不低于。
那么,为什么编译器首先在安全的上下文中允许这样的东西呢? 为什么它不需要具有显式布局的类型的不安全上下文,这些类型具有重叠字段?
我希望那里有人有答案 – 因为它必须有趣。
示例(所有编译都没有不安全的块,甚至不安全的开关):
[StructLayout(LayoutKind.Explicit)] struct ValueUnion { [FieldOffset(0)] public int i; [FieldOffset(0)] public float f; } [StructLayout(LayoutKind.Explicit)] struct ReferenceUnion { [FieldOffset(0)] public string str; [FieldOffset(0)] public Stream stream; } [StructLayout(LayoutKind.Explicit)] struct CLRWontLoad { [FieldOffset(0)] public string str; [FieldOffset(0)] public IntPtr ptr; }
让我回答一些略有不同的问题。
使用显式布局属性是否允许违反类型安全而不使用
unsafe
关键字?
是。 这就是它的用途。
编译器对
FieldOffset
属性有什么了解?
编译器validationFieldOffset
属性不在static / const字段上,并且它与StructLayout
属性一致。 它不会检查有关属性有效性的任何其他内容。
为什么C#编译器没有检测到属性的潜在不安全使用并需要
unsafe
关键字?
这是一个function。 为了供您使用,必须考虑,设计,指定,实施,测试,记录function并将其发送给客户。 这个function被认为是。 它没有设计,指定,实施,测试,记录或发货,因此没有这样的function。
这是一个令人不满意的答案。
我的建议是不要在StackOverflow上询问“为什么”这些问题。 “为什么”问题含糊不清,因此您经常得到不满意的答案。 “为什么不”这些问题更难以令人满意地回答,因为他们有这样一个假设,即世界不应该成为一种不是这样的方式的充分理由。
好的,让我改一下。 如果这个function是针对编译器设计团队的, 那么在决定是否继续使用该function时,他们可能会考虑哪些优缺点?
-
Pro:代码可以明确地以不安全的方式使用,因此应该要求
unsafe
关键字允许它。 -
Con:
unsafe
关键字用于防止意外使用危险的不安全function,这四十年的C向我们展示了即使是专业程序员也难以发现错误的function。 无法意外使用struct layout属性。 可以假设使用此属性的人确切地知道他们正在做什么,并且有充分的理由知道他们正在做什么。
在我看来,这里的优点超过了职业选手。 对于适中的成本,该function将是非常小的益处。
请记住,实现的每个function都意味着列表中的另一个function未实现,因为预算是有限的。 我不想做这个弱function,必须削减一个实际上让开发人员受益的function。
团队是否考虑过此function并在此基础上拒绝了该function?
是。 看到
这有点不可避免地最终成为循环解释。 它允许你使用工会违反类型安全,因为这是你使用工会的原因。 它不能省略该function,因为没有它就不能写出体面的pinvoke。 特别是winapi充满了工会。 并且pinvoke不是不安全的,它只是无法validation。 C#是一种非常实用的语言,如果你想拍摄你的腿,那么你就有资格。
它不是一个安全漏洞。 CLR真正关心的是可validation的代码。 C# unsafe关键字只有重叠,没有关键字的C#代码也不能自动validation。 使用pinvoke是最明显的例子。 CLR源代码在评论中很好地解释了它。 从clr / src / vm / class.cpp,MethodTableBuilder :: HandleExplicitLayout()函数:
// go through each field and look for invalid layout // (note that we are more permissive than what Ecma allows. We only disallow the minimum set necessary to // close security holes.) // // This is what we implment: // // 1. Verify that every OREF is on a valid alignment // 2. Verify that OREFs only overlap with other OREFs. // 3. If an OREF does overlap with another OREF, the class is marked unverifiable. // 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()). //
“OREF”表示“对象引用”。 规则3将kibosh写入真正不安全的代码,不可靠的代码只能完全信任。 规则2拒绝你的第三个例子。 那个有一个基本的cooties因为GC不能猜测对象引用是否有效所以不能保持对象存活。
有更多代码处理显式布局,例如,它还根据参与字段类型的信任来计算最小信任。 您可以在SSCLI20发行版中查看。
哦,现在你已经添加了一些例子。
编译器允许它,因为这段代码是安全的。 使用安全代码几乎可以完成使用不安全代码所做的一切。 这就是为什么没有人几乎不使用不安全的代码。
C#还允许您序列化一种类型并将其反序列化为另一种类型。 安全并不意味着没有错误。
- PresentationFramework.dll中发生’System.Reflection.TargetInvocationException’
- SFTP SSH.NET DLL而不是SharpSSH
- 为什么’stackalloc’关键字不适用于属性?
- 从头开始编写/绘制我自己的ListBox / ListView控件
- C#为打开的文件计算MD5?
- 未找到数据源名称且未指定默认驱动程序
- 无法激活Xamarin Unhanded ERROR – Visual Studio 2015更新2
- 无论.NET版本/环境如何,保证找到ildasm.exe和ilasm.exe文件的文件路径的方法?
- 使用时区解析ISO 8601到.NET datetime