【发布时间】:2017-06-08 04:35:40
【问题描述】:
我有一个 MCVE,它在我的一些机器上使用 g++ 4.4.7 版编译时会崩溃,但可以与 clang++ 3.4.2 版和 g++ 6.3 版一起使用。
我想知道它是来自未定义的行为还是来自这个古老版本 gcc 的实际错误。
代码
#include <cstdlib>
class BaseType
{
public:
BaseType() : _present( false ) {}
virtual ~BaseType() {}
virtual void clear() {}
virtual void setString(const char* value, const char* fieldName)
{
_present = (*value != '\0');
}
protected:
virtual void setStrNoCheck(const char* value) = 0;
protected:
bool _present;
};
// ----------------------------------------------------------------------------------
class TypeTextFix : public BaseType
{
public:
virtual void clear() {}
virtual void setString(const char* value, const char* fieldName)
{
clear();
BaseType::setString(value, fieldName);
if( _present == false ) {
return; // commenting this return fix the crash. Yes it does!
}
setStrNoCheck(value);
}
protected:
virtual void setStrNoCheck(const char* value) {}
};
// ----------------------------------------------------------------------------------
struct Wrapper
{
TypeTextFix _text;
};
int main()
{
{
Wrapper wrapped;
wrapped._text.setString("123456789012", NULL);
}
// if I add a write to stdout here, it does not crash oO
{
Wrapper wrapped;
wrapped._text.setString("123456789012", NULL); // without this line (or any one), the program runs just fine!
}
}
编译运行
g++ -O1 -Wall -Werror thebug.cpp && ./a.out
pure virtual method called
terminate called without an active exception
Aborted (core dumped)
这实际上是最小的,如果删除此代码的任何功能,它就可以正常运行。
分析
代码 sn-p 在使用 -O0 编译时可以正常工作,但是在使用 -O0 +flag 编译时,对于 -O1 的每个标志(如 GnuCC documentation 中定义的那样),它仍然可以正常工作。
生成一个核心转储,可以从中提取回溯:
(gdb) bt
#0 0x0000003f93e32625 in raise () from /lib64/libc.so.6
#1 0x0000003f93e33e05 in abort () from /lib64/libc.so.6
#2 0x0000003f98ebea7d in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib64/libstdc++.so.6
#3 0x0000003f98ebcbd6 in ?? () from /usr/lib64/libstdc++.so.6
#4 0x0000003f98ebcc03 in std::terminate() () from /usr/lib64/libstdc++.so.6
#5 0x0000003f98ebd55f in __cxa_pure_virtual () from /usr/lib64/libstdc++.so.6
#6 0x00000000004007b6 in main ()
请随时在 cmets 中询问测试或详细信息。 问:
是实际代码吗?是的!它是!一个字节一个字节。我已经检查并重新检查了。
-
你使用的是什么版本的 GnuCC?
$ g++ --version g++ (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16) Copyright (C) 2010 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 我们能看到生成的程序集吗?是的,here it is on pastebin.com
【问题讨论】:
-
我看不出这段代码有什么问题,甚至特别棘手。它应该编译并运行。如果它失败了,我会非常自信地说这是一个编译器错误。
-
我实际上碰巧有 g++ 4.4.6 对我来说很容易访问,并且该程序不会使用该 g++ 进行核心转储,因此它看起来很像 4.4.7 编译器错误。
-
有趣的是,GCC 6.2 将
main编译为无操作:godbolt.org/g/UByGsC - 这可能会掩盖编译器或代码中的潜在错误。 FWIW 我看不出代码有什么问题。当然也有可能编译器的错误(如果有的话)已经被修复了。 -
你能把汇编输出转储到某个地方吗?
-
@Slava here it is
标签: c++ g++ redhat undefined-behavior