我有一个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)
这实际上是最小的,如果删除此代码的任何功能,它就会正确运行。
当使用-O0
编译时,代码片段可以正常工作,但是对于GnuCC上定义的-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.
我们可以看到生成的程序集吗?是的,这是在 pastebin.com
虽然这个错误的真正解决方案是不使用RedHat GnuCC 4.4.7(或任何RedHat编译器…),但我们暂时只能使用这个版本。
我们确实找到了另一种选择:将BaseType
的构造函数混淆到编译器,从而防止它过度优化它。我们简单地通过在单独的翻译单元中定义BaseType::BaseType()
来做到这一点。
这样做绕过g错误。我们确实检查了BaseType
和TypeTextFix
虚拟表指针在调用其相关构造函数之前都被写入构造对象。
这是一个特定于红帽的错误,在FSF GCC中不存在。这不是代码中的问题。
在同时安装了CentOS 6的GCC和FSF GCC 4.4.7的系统上,生成了汇编列表并查看了两者之间的差异,有一点值得一提:
CentOS 6的GCC生成
movq $_ZTV8BaseType+16, (%rsp)
而FSF GCC 4.4.7生成
movq $_ZTV11TypeTextFix+16, (%rsp)
换句话说,Red Hat的一个GCC补丁使其错误地设置了vtable。这是您的main
函数的一部分,您可以在之后不久在您自己的程序集列表中看到它。L48:
。
Red Hat在其GCC版本中应用了许多补丁,其中一些是影响代码生成的补丁。不幸的是,其中一个似乎有一个意想不到的副作用。
在C 11中,我们能够声明一个析构函数是自动生成的: 此外,我们可以将析构函数声明为纯虚: 我的问题是:如何将析构函数声明为自动生成和纯虚拟?看起来以下语法不正确: 这一个也不是: 也不是这个: 编辑:关于问题目的的一些澄清。基本上,我希望一个空类是不可实例化的基类,但派生类是可实例化的,那么该类必须有一个纯虚拟析构函数。但另一方面,我不想在.cpp文件中提供定义。因此,我需要某种与等效的机制。我
我用不同的版本和代码更新了一个应用程序。然后通过“右键点击->Android Tools->Export signed application Package”使用以前版本apk的相同密钥库对apk进行签名。但在上传到google play时,却出现了以下错误。谁能告诉我我哪里不对劲吗? “上载失败您将一个使用不同证书签名的APK上载到以前的APK上。您必须使用相同的证书。您现有的APK使用带有指
在构建一个插件时,我会遇到一个“找不到类”的异常 有人已经设法创建了插件或类加载器XPages就这样杀死了?
本文向大家介绍C++中虚函数与纯虚函数的用法,包括了C++中虚函数与纯虚函数的用法的使用技巧和注意事项,需要的朋友参考一下 本文较为深入的分析了C++中虚函数与纯虚函数的用法,对于学习和掌握面向对象程序设计来说是至关重要的。具体内容如下: 首先,面向对象程序设计(object-oriented programming)的核心思想是数据抽象、继承、动态绑定。通过数据抽象,可以使类的接口与实现分离,使
问题内容: 我收到以下错误 尝试在空对象引用上调用虚拟方法’void android.widget.StackView.setAdapter(android.widget.Adapter)’ 在这条线上 完整的片段 EventsFragment.java 是 Stack_Adapter.java Stack_Items 问题答案: 您正在执行: 你是。返回。 你为什么用? 在哪里?您应该从正确的x
我的应用程序有问题,想解决它,但我无法访问解决方案,请帮帮我,,