正如Clang所指出的,这个代码真的没有定义吗



我在使用单元测试库Catch的项目上打开了-fsanitize=undefined。Catch中的一行被此标志标记为导致未定义的行为。我设法做了一个孤立的例子:

#include <iomanip>
#include <sstream>
int main()
{
std::ostringstream os; 
os << "0x" << std::setfill('0') << std::hex;
}

编制单位:

clang++ -fsanitize=undefined main.cpp

如果我运行此程序,将给出以下打印:

/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/ios_base.h:96:24: runtime error: load of value 4294967221, which is not a valid value for type 'std::_Ios_Fmtflags'
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/ios_base.h:76:67: runtime error: load of value 4294967221, which is not a valid value for type 'std::_Ios_Fmtflags'

这在clang3.6.0上发生在我身上,在clang3.4-1ubuntu3上发生在一个朋友身上。这在gcc版本4.9.2上不会发生

那上面是什么?这个代码真的很糟糕吗,或者clang的一端有什么可疑的东西吗?

这是libstdc++中的一个错误,来自标题为-fsanitize=未定义的cfe-dev邮件列表线程,共享库表示:

这是libstdc++中的一个错误。您将能够使用消毒液黑名单文件,一旦威尔的补丁登陆现在,手动过滤它们可能是您的最佳选择。

这里有一个修补程序;我会考虑把这个推到libstdc++将在未来几天向上游运行。[…]

正如我在评论中对dyp指出的,clang使用libstdc++而不是libc++的系统并不少见,如果我们通过-stdlib=libstdc++在Coliru上明确使用libstdc++进行测试,我们确实可以重现这个问题。

以下libstdc++错误报告:ios_base.h中的运算符~计算的错误枚举值涵盖了这个问题,并表示:

为ios_base.h中的枚举定义的重载运算符具有以下形式:

Enum operator~(Enum e) { return Enum(~static_cast<int>(e)); }

~在枚举的值范围之外创建值类型,因此返回枚举类型的强制转换具有未指定的值(请参阅[expr.static.cast]p10),并且在实践中它生成Enum值在Enum类型的可表示值范围之外,因此行为未定义。

参考[expr.static.cast]p10说:

积分或枚举类型的值可以显式转换为枚举类型。值为如果原始值在枚举值(7.2)的范围内,则保持不变。否则值未指定(可能不在该范围内)。浮点类型的值也可以转换到枚举类型。结果值与将原始值转换为基础值相同枚举的类型(4.9)以及随后的枚举类型。

正如hvd所说,这是形式上未指定的行为,但Richard指出,在实践中,这最终是未定义的行为。

T。C.指出,DR 1766将其从未指定行为更改为未定义行为:枚举值范围之外的值:

尽管问题1094澄清了枚举类型的表达式的值在转换为枚举类型后可能不在枚举值的范围内(见5.2.9[expr.static.cast]第10段),但结果只是一个未指定的值。鉴于未定义的行为会使表达式变得不恒定,因此可能应该加强这一点,以产生未定义行为。另见9.6[class.bit]第4段。

新的措辞出现在标准草案N4431中。

相关内容

最新更新