【问题标题】:Pure virtual method called - cross compiling纯虚方法调用——交叉编译
【发布时间】:2013-11-15 21:00:56
【问题描述】:

我正在编写一个用于 BeagleBone Black 的基于事件的编程库,但遇到了一个奇怪的错误。

当我用完全相同的标志编译完全相同的代码时,我在基于 ARM 的处理器上收到以下错误,但在我运行为我的 x86 计算机编译的代码时却没有。

$ ./missionControl
pure virtual method called
pure virtual method called
pure virtual method called
terminate called recursively
terminate called recursively
Aborted

当我在笔记本电脑上编译和运行时,程序运行正常

这是我用来编译的命令(ish,我使用的是 Makefile,但两种编译方法都表现出完全相同的行为):

g++ -std=gnu++11 -pthread -O3 -D_GLIBCXX_USE_NANOSLEEP -o missionControl `find . -name *.cpp`

不管我在实际 BeagleBone 上与 Ubuntu 的 arm-linux-gnueabi-g++ 还是与 ARM 兼容的 g++ 进行交叉编译,我仍然在 ARM 上遇到错误。

我的问题是:什么可能导致此错误,我可以做些什么来尝试找到源?为什么相同版本的 G++ 会在一种处理器架构上发生这种情况,而在另一种处理器架构上却不会?

谢谢!

这是来自 ARM 处理器的 GDB 的回溯:

#0  0xb6d4adf8 in raise () from /lib/libc.so.6
#1  0xb6d4e870 in abort () from /lib/libc.so.6
#2  0xb6f50ab4 in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/libstdc++.so.6
#3  0xb6f4ea4c in ?? () from /usr/lib/libstdc++.so.6
#4  0xb6f4ea4c in ?? () from /usr/lib/libstdc++.so.6
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

【问题讨论】:

  • 您可能在管理某些多态对象或对象集合的生命周期时出错。当您尝试删除已删除的内容时,通常会显示该错误。
  • 这个错误发生在我启动我的程序之前,在任何东西都会被删除之前(我认为)......我在整个程序中使用智能指针,并且 valgrind 报告没有错误并且所有内存都被释放在 x86 上正确运行的程序结束时。
  • 嗯...尝试减少问题?删除全局变量直到它起作用?您确定错误发生在 main 被调用之前?
  • @KerrekSB 我不确定它是否在调用 main() 之前。让我尝试在 main() 的顶部添加一个cout。我唯一拥有的全局变量是一个翻译单元中的互斥体,所以我会尝试将它纳入一个类。
  • 我也有同样的问题 - 我猜没有多少人在 beagleboard 上使用 std::thread 吧?

标签: c++ cross-compiling embedded-linux virtual-functions g++-4.7


【解决方案1】:

这个问题原来是由于在 BeagleBone 上运行的 ARM 版本的 libstdc++ 中的一个错误造成的。一个根本没有虚函数的小玩具程序在创建 std::thread 时会导致同样的错误(“调用纯虚函数”)。

我将尝试在 BeagleBone 本身上编译 gcc/libstdc++ 4.8 的自定义版本——即使这需要很长时间。

【讨论】:

  • 我最终从 BeagleBone 上清除了糟糕的 Angstrom linux,并用 Ubuntu 取而代之。交叉编译按预期工作。对于使用这款出色设备的任何人:擦除它并安装 Ubuntu。
  • 您最终是否尝试构建 gcc?还是你放弃了,直接去 Ubuntu?
  • 我尝试构建 gcc。构建中途失败。我擦了擦,然后去了 Ubuntu。
【解决方案2】:

pure virtual method called 错误发生在您尝试使用动态调度在基类中调用纯虚拟函数时,该函数在实现它的派生类型之前或之后被破坏了。

最常见的原因是基类试图通过构造函数或析构函数调用在此级别纯的虚函数。除此之外,正如某些 cmets 中指出的那样,如果您尝试访问死对象,您也可能会遇到同样的问题。

只需将调试器附加到程序中,然后查看调用了哪些虚函数以及从何处调用。

【讨论】:

  • 您能否提供有关如何使用 GDB 查找此错误的提示?如果我让它运行并崩溃,则回溯不是很有帮助。我为我的问题添加了回溯。
  • 另外,为什么这只发生在 ARM 上?相同的编译器版本可以在 x86 上生成良好的代码。
  • 我刚刚将所有纯虚函数替换为常规虚函数,打印函数名称然后调用abort()。我仍然遇到同样的问题并且我插入的错误消息永远不会被打印出来。
【解决方案3】:

见:https://groups.google.com/forum/#!topic/automatak-dnp3/Jisp_zGhd5I

还有:Why does this simple c++11 threading-example fail, when compiled with clang 3.2?

现在,我不知道为什么会这样,但至少对我有用。将以下四个预处理器定义添加到编译器命令行:

__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8

我还没有试验过它们是否都是必需的,或者你是否可以只用一些。但这为我解决了问题。感谢那些写出上述答案的人,也感谢我的同事在谷歌上搜索我:)

【讨论】:

    猜你喜欢
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 2017-07-27
    • 1970-01-01
    • 2019-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多