C#中有趣的类型系统冲突(在安全上下文中)

C#中有趣的类型系统冲突(在安全上下文中),c#,.net,C#,.net,我所说的类型系统冲突是在模拟联合时发生的 为什么在安全的环境下允许这样做 它允许您将值类型作为不同的值类型进行处理-您可以通过以下方式实现: 浮球f=2.5f int-binaryidentialint=*((int*)&f) 它允许您引用X类型的对象,就像它引用Y类型的对象一样,即使这些类型之间没有关系 它允许您创建CLR甚至不会加载的类型(如果重叠字段中至少有一个是引用类型,并且其中至少有一个是值/指针类型-CLR将拒绝加载)。我希望C#编译器比CLR更挑剔它所允许的内容。不少 那么,为

我所说的类型系统冲突是在模拟联合时发生的

为什么在安全的环境下允许这样做

  • 它允许您将值类型作为不同的值类型进行处理-您可以通过以下方式实现:

    浮球f=2.5f
    int-binaryidentialint=*((int*)&f)

  • 它允许您引用X类型的对象,就像它引用Y类型的对象一样,即使这些类型之间没有关系

  • 它允许您创建CLR甚至不会加载的类型(如果重叠字段中至少有一个是引用类型,并且其中至少有一个是值/指针类型-CLR将拒绝加载)。我希望C#编译器比CLR更挑剔它所允许的内容。不少

那么,为什么编译器首先允许在安全上下文中执行这些操作呢?为什么它不需要显式布局的类型的不安全上下文,这些类型有重叠的字段

我希望有人能给出答案——因为它必须有趣

示例(所有编译都没有不安全的块,甚至没有不安全的开关):


哦,现在您已经添加了示例

编译器允许它,因为此代码是安全的。几乎所有使用不安全代码的操作都可以使用安全代码完成。这就是为什么几乎没有人使用不安全的代码


C#还允许您序列化一种类型并将其反序列化为另一种类型。安全并不意味着没有bug。

这在某种程度上不可避免地成为一种循环解释。它允许您使用联合来违反类型安全,因为这就是您使用联合的目的。它不能忽略这个特性,因为没有它你就写不出像样的pinvoke。尤其是winapi充满了联合。pinvoke并不是不安全的,它只是无法验证。C#是一种非常实用的语言,如果你想把你的腿射下来,那么你有权这么做

这不是一个安全漏洞。CLR真正关心的是可验证代码。C#unsafe关键字仅具有重叠,没有该关键字的C#代码也不能自动验证。平沃克就是最明显的例子。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”是指“对象引用”。第三条规则禁止编写真正不安全的代码,无法验证的代码只能在完全信任的情况下运行。规则2拒绝了你的第三个例子。这是因为GC无法猜测对象引用是否有效,因此无法保持对象的活动状态


有更多的代码处理显式布局,例如,它还基于参与字段类型的信任计算最小信任。您可以查看SSCLI20发行版。

让我回答一些稍微不同的问题

使用显式布局属性是否允许在不使用
unsafe
关键字的情况下违反类型安全

对。这就是它的目的

编译器对
FieldOffset
属性有哪些知识

编译器验证
FieldOffset
属性不在静态/const字段上,并且它与
StructLayout
属性一致。它不会检查有关属性有效性的任何其他内容

为什么C#编译器没有检测到该属性的潜在不安全使用,并要求使用
unsafe
关键字

这是一个特点。为了供您使用,必须考虑、设计、指定、实施、测试、记录功能,并将其发送给客户。这一特点被考虑到了。它没有设计、指定、实施、测试、记录或装运,因此没有此类功能

这是一个令人不满意的答案

我的建议是不要问关于StackOverflow的“为什么”问题。“为什么”的问题是模糊的,因此你经常会得到不满意的答案。“为什么不”的问题更难令人满意地回答,因为它们有一个前提,那就是世界需要有一个很好的理由,让它不成为一个不可能的世界

好的,让我换一种说法。如果这个特性被绑定到编译器设计团队,<强> >在决定是否继续执行这个特性时,他们会考虑什么样的缺点?
  • 赞成:代码显然可以以不安全的方式使用,因此应该需要
    unsafe
    关键字来允许它

  • 缺点:
    unsafe
    关键字用于防止意外使用危险的不安全特性,四十年的C语言已经向我们表明,即使是专家程序员也很难发现错误。无法意外使用struct layout属性。可以假设使用此属性的人确切地知道他们在做什么,并且有很好的理由说明他们在做什么

在我看来,这里弊大于利。这项功能的好处很小,但成本适中

记住,每个实现的特性都意味着列表中的另一个特性没有实现,因为预算是有限的。我不想做这个薄弱的功能,必须削减一个实际上有利于开发人员的功能

团队是否考虑过此功能并基于这些理由拒绝了它

对。看


什么是“安全上下文”?不在不安全区块内的所有内容err,你有任何代码来证明你的意思吗?@EricLippert对于
unsafe
关键字我可以同意。但是我看不出编译器开关有什么意义,它不允许某些内存损坏行为,但不是全部。@CodesInChaos:开关的意义不是不允许所有内存损坏行为;切换的目的不是禁止任何事情!切换的要点是确保开发人员在没有充分审查的情况下不会向项目中添加不安全的代码块。当我们
// 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()).
//