以下代码在 clang 中崩溃(x86_64-pc-linux-gnu 上的版本 5.0.0-3~16.04.1),但在 gcc (9.2.0) 中运行良好。
struct Registry {
static int registerType(int type) {
std::cout << "registering: " << type;
return type;
}
};
template<typename T>
struct A {
static int i;
};
template<typename T>
int A<T>::i = Registry::registerType(9);
int main() {
std::cout << A<int>::i << std::endl;
}
根据地址清理程序,clang 崩溃的原因是:
ASAN:DEADLYSIGNAL
=================================================================
==31334==ERROR: AddressSanitizer: SEGV on unknown address 0xffffffffffffffe8 (pc 0x7f5cc12b0bb6 bp 0x7ffdca3d1a20 sp 0x7ffdca3d19e0 T0)
==31334==The signal is caused by a READ memory access.
#0 0x7f5cc12b0bb5 in std::ostream::sentry::sentry(std::ostream&) /root/orig/gcc-9.2.0/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/ostream.tcc:48:31
#1 0x7f5cc12b11e6 in std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) /root/orig/gcc-9.2.0/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/ostream_insert.h:82:39
#2 0x4197a7 in __cxx_global_var_init.1 (/tmp/1576534654.656283/a.out+0x4197a7)
#3 0x514eac in __libc_csu_init (/tmp/1576534654.656283/a.out+0x514eac)
#4 0x7f5cc02847be in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:247
#5 0x419858 in _start (/tmp/1576534654.656283/a.out+0x419858)
这是 clang 中漂亮计数器习惯用法的错误,还是格式不正确的静态初始化顺序惨败的示例?
Edit
根据接受的答案,问题可以改写为:
- 难道全球
ostream
object std::cout
是不是没有正确初始化?
- 是否存在允许编译器不具有的有效情况
std::cout
初始化,即使我们包含 iostream 并且我们使用std::cout
适当地?
- 是否存在在普通设备上崩溃的用例
cout << "foo"
是不是编译器bug?
为了避免剧透,我只是暗示答案是Yes。这种情况可能会发生,但不用担心,有解决方法。想看更多请关注下面接受的答案.
同样根据接受的答案,所讨论的情况可以缩小到一个更基本的场景:
int foo() {
std::cout << "foo";
return 0;
}
template<typename T>
struct A {
static int i;
};
template<typename T>
int A<T>::i = foo();
int main() {
(void) A<int>::i;
}
在上述 clang 版本上崩溃(看起来,这是合理的!)。