c++ - 正如 Clang 似乎表明的那样,这段代码真的是未定义的吗?

标签 c++ clang undefined-behavior libstdc++ sanitizer

我在使用单元测试库 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'

这发生在我使用 clang 3.6.0 和使用 clang 3.4-1ubuntu3 的 friend 身上。我在 gcc 版本 4.9.2

上不会发生这种情况

那么这里是什么?这段代码真的很糟糕,还是在 clang 的末尾有什么可疑的地方?

最佳答案

这是一个 bug in libstdc++ ,来自 cfe-dev 邮件列表线程,标题为 -fsanitize=undefined and shared libraries 说:

This is a bug in libstdc++. You will be able to work around it with a sanitizer blacklist file, once Will's patch for that lands, but for now, filtering them out manually is likely to be your best option.

Here's a patch to fix it; I'll be looking into pushing this to libstdc++ upstream in the next few days. [...]

正如我在评论中提到的 dyp ,看到 clang 使用 libstdc++ 而不是 libc++ 的系统并不少见,如果我们在 Coliru explicitly using libstdc++ 上进行测试通过 -stdlib=libstdc++ 我们确实可以重现该问题。

以下 libstdc++ 错误报告:bad enum values computed by operator~ in ios_base.h涵盖了这个问题并说:

The overloaded operator~s defined for the enumerations in ios_base.h have the following form:

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

The ~ creates values outside the range of values of the enumeration type, so the cast back to the Enum type has an unspecified value (see [expr.static.cast]p10), and in practice it produces an Enum value outside the range of representable values for the Enum type, so behavior is undefined.

供引用[expr.static.cast]p10 说:

A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is unchanged if the original value is within the range of the enumeration values (7.2). Otherwise, the resulting value is unspecified (and might not be in that range). A value of floating-point type can also be converted to an enumeration type. The resulting value is the same as converting the original value to the underlying type of the enumeration (4.9), and subsequently to the enumeration type.

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

T.C.指出 DR 1766: Values outside the range of the values of an enumeration 将其从未指定行为更改为未定义行为:

Although issue 1094 clarified that the value of an expression of enumeration type might not be within the range of the values of the enumeration after a conversion to the enumeration type (see 5.2.9 [expr.static.cast] paragraph 10), the result is simply an unspecified value. This should probably be strengthened to produce undefined behavior, in light of the fact that undefined behavior makes an expression non-constant. See also 9.6 [class.bit] paragraph 4.

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

关于c++ - 正如 Clang 似乎表明的那样,这段代码真的是未定义的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30122500/

相关文章:

iOS8 SDK 的静态分析器错误

c++ - 从覆盖函数调用覆盖函数

c++ - boost odeint 是否支持通过 Boost.Units 进行维度分析?

c++ - 如何对其他子系统隐藏一个类

ios - 使用 clang 集成汇编器为 iOS 5.1 编译 NEON 时出错

c - 为什么这些构造使用增量前和增量后未定义的行为?

c++ - 没有任何库的正弦函数

c - 为函数参数指定寄存器?

c++11 - std::shared_ptr 和 dlopen(),避免未定义的行为

c - c 程序的意外行为?