Source:Uninitialized garbage on ia64 can be deadly
在ia64上,每个64位寄存器实际上是65位。额外的一点 被称为" NaT"代表"不代表"。该位设置为 寄存器不包含有效值。把它想象成 浮点NaN的整数版本。
NaT位最常见于推测执行。那里 是ia64上一种特殊形式的加载指令 从内存加载值,但如果加载失败(因为内存 被分页或地址无效),而不是提出一个 页面错误,所有发生的事情是NaT位被设置和执行 继续进行。
NaT的所有数学运算都会再次产生NaT。
源文章接着解释了在推测加载期间寄存器如何最终具有NaT表示并发出以下注释:
从pp表示的其他堆栈溢出答案中可以看出, "任何类型(unsigned char除外)都可能有陷阱表示"。你知道,如果你有一个价值为NaT的寄存器,你就是这么多 以错误的方式呼吸它(例如,尝试将其值保存到 内存),处理器将引发STATUS_REG_NAT_CONSUMPTION 异常。
此link表示
标准对访问未初始化的唯一保证 数据是unsigned char类型没有陷阱表示,和 填充没有陷阱表示。
如果这样的寄存器(具有NaT位设置的寄存器)被分配用于存储未初始化的无符号字符(类似于下面的缺陷报告中的代码片段),那么如何根据ISO C11处理它?</ p>
下面的缺陷报告是否指向同一问题,是否在ISO C11中得到纠正?
如果不是如何处理这种特殊情况?
如果左值指定一个自动存储持续时间的对象 本来可以用寄存器存储类声明(从来没有它的 地址被取消),该对象未初始化(未声明为 初始化程序,并且之前没有执行任何赋值 使用),行为未定义
在缺陷报告的最后添加上面的#34;更改为C1X&#34;处理这种情况?
以下功能在C90下具有未定义的行为,但会出现 根据C99严格遵守
int foo(void) {
unsigned char uc;
return uc + 1 >= 0;
}
答案 0 :(得分:4)
首先,如果您还没有亲眼看到它,您可以从here(see also)获取C11标准的最终草稿。
DR中的文本确实已添加到第6.3.2.1节p2中,这使得代码根据C11未定义。
标准中关于陷阱表示的部分继续排除unsigned char
可以有陷阱表示的可能性 - 但这无关紧要。这里需要注意的是,正如DR提到的2008年春季记录所提到的那样,从标准的角度来看,这实际上根本不需要涉及陷阱表示(它们只是UB可能引起的一种机制)金属上的问题)。问题实际上是关于未初始化的自动值;修改后的段落通过澄清unsigned char
仅仅因为一个类型特定属性而被视为免除一般类型的UB而解决了这个问题(不是通过为该属性添加更多复杂性。)
你可以想象,就像NaT位是IA64上整数的实现细节一样,陷阱表示的缺失是C类型的一般族中一种特定类型的“实现细节”。变量的实际类型是次要的一般规则,您不应该感到安全访问未初始化的任何变量;添加澄清了优先权。