Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ &引用;纯虚拟函数称为;在gcc 4.4上,但不在更新版本或clang 3.4上_C++_G++_Redhat_Undefined Behavior - Fatal编程技术网

C++ &引用;纯虚拟函数称为;在gcc 4.4上,但不在更新版本或clang 3.4上

C++ &引用;纯虚拟函数称为;在gcc 4.4上,但不在更新版本或clang 3.4上,c++,g++,redhat,undefined-behavior,C++,G++,Redhat,Undefined Behavior,我有一个MCVE,在我的一些机器上,当使用g++版本4.4.7编译时会崩溃,但在使用clang++版本3.4.2和g++版本6.3时确实会崩溃 我想知道它是来自未定义的行为还是来自这个古老版本的gcc的实际bug 代码 这实际上是最小的,如果删除此代码的任何功能,它将正确运行 分析 使用-O0编译时,代码段工作正常,但对于上定义的-O1的每个标志,使用-O0+标志编译时,代码段仍然工作正常 将生成一个核心转储,从中可以提取回溯: (gdb) bt #0 0x0000003f93e32625 i

我有一个MCVE,在我的一些机器上,当使用g++版本4.4.7编译时会崩溃,但在使用clang++版本3.4.2和g++版本6.3时确实会崩溃

我想知道它是来自未定义的行为还是来自这个古老版本的gcc的实际bug

代码 这实际上是最小的,如果删除此代码的任何功能,它将正确运行

分析 使用
-O0
编译时,代码段工作正常,但对于上定义的
-O1
的每个标志,使用
-O0+标志编译时,代码段仍然工作正常

将生成一个核心转储,从中可以提取回溯:

(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 ()

请随时在评论中询问测试或详细信息。 问:

  • 这是实际代码吗?对它是!一个字节接一个字节。我检查了又检查

  • 您使用的GnuCC du的确切版本是什么

    $ 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.
    
  • 我们能看到生成的程序集吗?对


这是FSF GCC中不存在的红帽特定错误。这在代码中不是问题

在同时具有CentOS 6的GCC和FSF GCC 4.4.7的系统上,两者都生成程序集列表并查看两者之间的差异,会跳出一位:

CentOS 6的GCC生成

movq $_ZTV8BaseType+16, (%rsp)
movq $_ZTV11TypeTextFix+16, (%rsp)
鉴于FSF GCC 4.4.7生成

movq $_ZTV8BaseType+16, (%rsp)
movq $_ZTV11TypeTextFix+16, (%rsp)
换句话说,Red Hat的一个GCC修补程序使其无法正确设置vtable。这是
main
函数的一部分,您可以在
之后不久在自己的程序集列表中看到它。L48:


Red Hat在其GCC版本中应用了许多补丁,其中一些补丁会影响代码生成。不幸的是,其中一个似乎有一个意外的副作用。

虽然这个错误的真正解决方案是不使用RedHat GnuCC 4.4.7(或任何RedHat编译器…),但我们暂时仍使用这个版本

我们确实找到了另一种选择:将
BaseType
的构造函数与编译器混淆,从而防止它过度优化。我们只需在一个单独的翻译单元中定义
BaseType::BaseType()


这样做可以绕过g++错误。我们确实检查了
BaseType
TypeTextFix
虚拟表指针在调用构造对象的相关构造函数之前是否都写入了构造对象。

我看不出这段代码有任何错误,甚至没有特别棘手的地方。它应该编译并运行。如果它失败了,我会很有信心地说这是一个编译器错误。实际上,我碰巧有一个g++4.4.6很容易访问,并且程序没有使用该g++进行内核转储,因此它看起来非常像一个4.4.7编译器错误。有趣的是,GCC 6.2将
main
编译为no op:-这可能会掩盖编译器或代码中潜在的错误。FWIW我看不出代码有什么问题。当然,也有可能编译器错误(如果有的话)已经被修复。你能将程序集输出转储到某个地方吗?@Slava我真的希望Red Hat停止这样的修补。选中此项,可以确认。@LightnessRacesinOrbit我有大量redhat的gcc 2.96。我可以把这个叫做“古老的”对吗?;@谢谢,明天早上我会测试确认的。@YSC:嘿,真的!在一个单独的翻译单元中定义
BaseType
的构造函数确实修复了(事实上,隐藏了)这个bug:
BaseType
TypeTextFix
虚拟表都是编写的。谢谢!我可以把你的答案编辑成包含那个黑客代码以备将来参考吗?