2014-10-19 40 views
9

Source:Uninitialized garbage on ia64 can be deadly陷阱表示,无符号的字符和IA64的NaT

在IA64中,每个64位寄存器实际上是65位。额外的位 被称为“NaT”,代表“不是一件事”。该位在 寄存器不包含有效值时置位。把它看作浮点数NaN的整数版本 。

NaT位最常从推测执行中设置。其中 是ia64上的一种特殊的加载指令形式,它试图从内存中加载值,但是如果加载失败(因为内存 被换页或地址无效),则不会产生页面错误 ,所发生的只是NaT位被设置,并且执行 继续。

对NaT的所有数学运算只是再次产生NaT。

源文章接着解释寄存器如何能最终有投机性的加载过程中在NAT表示,并提出以下备注:

对于你看,如果你有一个寄存器的值是NaT和你这么多的呼吸错误的方式(例如,尝试将其值存储到 内存),处理器将引发一个STATUS_REG_NAT_CONSUMPTION 异常。

似乎从其它堆栈溢出的答案是,
“任何类型的(除了无符号字符)可以具有陷阱的表示”陷阱表示。

link

的唯一保证标准给出有关访问未初始化 数据是unsigned char类型有没有陷阱交涉,并 是填充有没有陷阱表示。

如果这样的寄存器(具有NAT的寄存器位被设置)被分配用于存储一个未初始化的无符号字符(类似于从下面的缺陷报告的代码片段),这是怎么根据ISO C11处理?

下面的缺陷报告是否指向相同的问题,并在ISO C11中纠正?

如果不是这个特殊情况如何处理?

如果左值指定该 可能已被宣布与寄存器存储自动存储时间的对象(从来没有考虑其 地址),而该对象未初始化(不与 初始申报,并没有分配到它已被执行之前 使用),其行为是未定义

确实上述加成在节“为C1X变化”缺陷报告末尾处理这种情况?

defect_report

了以下功能未定义C90下的行为,但似乎 要严格C99下符合

int foo(void) { 
     unsigned char uc; 
     return uc + 1 >= 0; 
    } 
+0

@Hasturkun - 感谢编辑 – 2014-10-19 15:28:35

+1

TL; DR NaT根本不是陷阱表示。它涉及一个硬件位,告诉硬件或硬件;但该位不是*类型*的一部分。它从硬件的角度来看属于一个特定的内存位置或寄存器,但就C而言它并没有多大意义。就像可以通过算术运算翻转的溢出位不是任何C值的一部分。与NaN进行比较和对比。 – 2014-10-20 05:40:11

+0

@ n.m - 有问题的缺陷报告似乎表明这是一个陷阱表示? “在某些硬件(例如Itanium)上,一个8位值可能有多达257个不同的值(0-255和”Not a Thing“值)。但是,c99明确禁止这样的值作为无符号字符。 – 2014-10-20 06:02:59

回答

4

第一件事,如果你还没有自己看过,你可以从获取C11标准的最终草案0(see also)。

来自DR的文本确实被添加到6.3.2.1 p2节,这使得代码根据C11被剪裁成undefined。

关于陷阱表示标准的章节继续排除unsigned char可能具有陷阱表示的可能性 - 但这并不重要。这里需要注意的是,正如2008年春季的备注中所提到的,从标准的角度来看,这实际上并不需要涉及陷阱表达本身(它们只是UB可能导致你在金属上的问题)。这个问题实际上是关于未初始化的自动值;修正段落通过澄清unsigned char应该被(未通过增加更多的复杂性给该属性)考虑免除的仅仅是因为它的特定于类型的属性的一个一般类型的UB可解决此。

您可以想象,就像NaT位是IA64上整数的实现细节一样,缺少陷阱表示是一般C类系列中的一种特定类型的“实现细节”。变量的实际类型次于更一般的规则,即您不应该安全地访问任何未初始化的变量;该增加澄清了优先顺序。

+0

谢谢,为什么填充被排除/标准保证没有陷阱表示? – 2014-10-20 04:42:53

+0

填充不能有陷阱表示,因为填充不是真的数据吗?你不能自己访问它;你可能(如果复制)以字节形式访问它。 – Leushenko 2014-10-20 05:17:50