为什么使用-fsanitize = undefined会导致“undefined reference to typeinfo”?

13
以下测试用例是从一个真实应用程序精简而来,使用-fsanitize=undefined(使用GCC 6.1.1)将无法链接,但不使用它则可以正常链接。有人能告诉我为什么吗?似乎与Qt / QObject、-fvisibility=hidden-fsanitize=undefined的组合有关,但具体问题出在哪里我不得而知。 lib1.h:
#include <QObject>

class MyObject : public QObject
{
public:
    MyObject (QObject * parent = nullptr);
    ~MyObject ();

    void myMethod ();
};

lib1.cc:

#include "lib1.h"

#define EXPORT __attribute__((visibility("default")))

EXPORT MyObject::MyObject (QObject * parent) : QObject (parent)
{
}

EXPORT MyObject::~MyObject ()
{
}

EXPORT void MyObject::myMethod ()
{
}

lib2.cc:

#include "lib1.h"

void test (MyObject * object)
{
    object->myMethod ();
}

构建步骤:

LIBFLAGS="-fPIC -shared -Wall -Wl,-z,defs"
QTFLAGS="-I/usr/include/qt -I/usr/include/qt/QtCore -lQt5Core"

g++ -fsanitize=undefined -fvisibility=hidden \
 ${QTFLAGS} ${LIBFLAGS} lib1.cc -o lib1.so

g++ -fsanitize=undefined \
 ${QTFLAGS} ${LIBFLAGS} lib1.so lib2.cc -o lib2.so

构建输出(来自最终步骤):

/tmp/ccY7PHv4.o:(.data.rel+0x18): undefined reference to `typeinfo for MyObject'
collect2: error: ld returned 1 exit status
2个回答

17
实际问题的答案是,-fsanitize=undefined 其实是一组包括 vptr 检查器在内的检查工具。
参考链接:https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html vptr 检查器需要运行时类型信息(RTTI),而其他回答已经解释了为什么它不可用。
要运行除了 vptr 之外的所有测试,可以输入以下命令:
-fsanitize=undefined -fno-sanitize=vptr

2

我认为-fsanitize=undefined只是一个转移注意力的话题。

你只是在导出该类的成员函数。为了还要导出它的元数据(例如其类型信息和可能的v-table指针),你需要导出这个

试试这个:

class EXPORT MyObject : public QObject
{
public:
    MyObject (QObject * parent = nullptr);
    ~MyObject ();

    void myMethod ();
};

那么您就不需要标记单个成员函数。

这意味着会有一些麻烦,因为EXPORT现在必须在公共头文件中定义,并且需要在Windows构建时在dllimport和dllexport之间切换。但是我已经阅读了更多资料,这似乎是推荐的做法。 - John Lindgren
我相信无论在Windows上,你都需要它来装饰符号名称。请参见https://dev59.com/53A65IYBdhLWcg3wqAWt。 - Arvid
定义“需要”。:) 十年磨一剑,我们在Windows上构建这个应用程序多年,而没有在公共头文件中使用任何dllimport/dllexport。就像示例中标记单个函数实现一样,这已经足够使所有内容编译并运行得很愉快了。 - John Lindgren
MSVC有一个更长的传统,即默认情况下不导出所有内容(即需要dllexport),并且可能在90年代后期解决了所有这些边缘情况。也许可以自动导出类元数据,如果您导出其中的某些部分。尽管如此,这只是我的假设。 - Arvid
@Arvid 如果没有它,链接还能正常,那怎么可能是个红鱼?我的代码也遇到了完全相同的问题(第三方编译时没有启用RTTI),在没有ubsan的情况下可以编译成功,但使用ubsan却会出现这个错误。 - xaxxon
@Arvid 找到了真正的答案并发布了它 - sanitize=undefined 包括 vptr sanitizer,这会导致对 RTTI 数据的依赖。 - xaxxon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接