如果我将以下代码放在test.cpp
中#include <fstream>
int main(int argc, char ** argv) {
std::ifstream a;
do{
a.widen('\n');
}while(true);
}
并使用
调用g ++g++ -O1 -fdevirtualize -flto -m64 -o out Tergiversative.cpp
在g ++版本5.1.0上,生成的可执行文件在第一次调用a.widen
时崩溃。如果我把它包裹在(例如)
do{
a.widen('\n');
}while(false);
因为它只是&#34;扁平化&#34;,但它确实发生在任何其他循环中,如
int i=2;
do{
a.widen('\n');
i--;
}while(i>0);
具体而言,在ctype<char>
widen
内,它到达(来自locale_facets.h
)
widen(char __c) const{
if (_M_widen_ok)
return _M_widen[static_cast<unsigned char>(__c)];
this->_M_widen_init();
return this->do_widen(__c);
}
它对do_widen
进行虚拟调用。当上述三个标志中的任何一个被禁用时,这样可以正常工作;当所有三个都启用时,vtable不会以某种方式正确填充,并且do_widen指针保持为NULL,在运行时给出SIGSEGV。当它没有被置于一个循环中(或者是一个简单的循环,比如do / while(false)),那么g ++会将上述内容转换为对std::basic_ios<char,std::char_traits<char>>::widen('\n')
的调用,并且没有任何不好的事情发生。
我的代码调用未定义的行为有什么问题吗?或者这是一个奇怪的边缘情况,在我触发的某些优化中?我只是在构建64位可执行文件(-m32
使其运行正常)时才会发生这种情况,而且只有-O1 -fdevirtualize -flto
。我检查了由-O1
转换的每个子标志,但它们没有触发它,所以它必须是&#34;隐形&#34;之一。优化直接检查-On
级别。 -fdevirtualize
相关的{{1}}是有意义的,因为它是一个失败的虚拟电话 - 但是 电话没有被虚拟化了。 vtable只是无人居住。
任何帮助理解这一点都将不胜感激!