如何在 Xcode 中追踪"libc++abi.dylib: Pure virtual function called!"

How to track down "libc++abi.dylib: Pure virtual function called!" in Xcode

本文关键字:Pure virtual function called dylib libc++abi Xcode 追踪      更新时间:2023-10-16

我有一个多线程OSX应用程序,它混合使用C++、Objective-C和Swift。

当我的应用程序关闭时,我在Xcode调试器窗口中看到:

libc++abi.dylib: Pure virtual function called!

我知道这个错误通常是由调用C++类构造函数或析构函数中的虚拟函数引起的。

有没有一种简单的方法可以找到它在哪里?我所说的"Easy"是指"不分析每个构造函数的每一行的调用树,也不分析每个具有虚拟函数的类的析构函数"。

我看不到堆栈痕迹。打印此消息时,调试器不会停止程序。在此消息之前,我的应用程序代理的applicationDidTerminate方法记录了一条消息。

我尝试在"所有异常"上设置一个断点,但不幸的是,使用大量异常的代码经常会碰到这个断点。是否有其他符号可以放置断点?

C++标准库定义了一些实现低级语言/库功能的"ABI"函数。libc++有一个很好的文档在这里描述了它们。

其中之一是__cxa_pure_virtual,当程序以某种方式调用纯虚拟函数时,就会调用它。因此,如果你在那里设置了一个断点,你应该能够找到发生这种情况的地方。

通常,当从构造函数或析构函数中调用虚拟函数时,会发生纯虚拟函数调用,而vtable处于中间状态。有关详细信息,请参阅此答案。

首先,它很可能是在析构函数中进行的,其中调用的是纯虚拟函数,而不是构造函数(不能保证,但很可能)。

如果在调用纯虚拟函数时编译器正在生成异常,那么您可以通过使用set_terminate()设置自己的终止处理程序来捕获它(例如,此处解释)。然后,您可以在终止处理程序中设置一个断点,以查看代码是如何到达该点的。

如果在调用纯虚拟函数时编译器没有生成异常(更可能的情况),那么您可以尝试添加自己的伪类,以帮助缩小发生违规调用的范围。只要让这些伪类在它们的析构函数中打印一些东西,并确保它们在发生事情时被删除,这有助于缩小范围。例如,在main()函数的开头放一个,如果你看到它的消息被打印出来,那么当静态对象被删除时,就会发生有问题的调用,因为这个伪对象将是main()返回之前最后一个被删除的对象。您可以通过添加这样的伪类作为您可以修改的其他类的第一个数据成员来做类似的事情,但您需要了解导致违规的纯虚拟函数调用的对象被删除的情况。

最后,如果有用的话,您实际上可以为纯虚拟函数提供一个实现,并且这些函数实际上可以被调用(是的,这是合法的C++)。如果您知道被调用的确切的纯虚拟函数,那么您可以为它提供一个实现,并在其中放置一个断点来捕获堆栈跟踪。这取决于你确切地知道被调用的纯虚拟函数,而你的问题表明这可能是未知的。