为什么 -fsanitize=undefined 会导致 "undefined reference to typeinfo"?
Why does -fsanitize=undefined cause "undefined reference to typeinfo"?
以下测试用例,从真实世界的应用程序中减少,无法 link -fsanitize=undefined
(使用 GCC 6.1.1),但 link 没有它也很好。谁能告诉我为什么?
似乎与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
我认为 -fsanitize=undefined
是一个转移话题。
您只是在导出 class 的成员函数。为了同时导出其元数据(如其类型信息和潜在的 v-table 指针),您需要导出 class.
试试这个
class EXPORT MyObject : public QObject
{
public:
MyObject (QObject * parent = nullptr);
~MyObject ();
void myMethod ();
};
那么您应该不需要标记各个成员函数。
所问实际问题的答案是 -fsanitize=undefined
实际上是一组消毒剂,包括 vptr
消毒剂。
https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
vptr
sanitizer 被清楚地标记为需要 RTTI,其他答案已经描述了为什么它不可用。
对运行所有测试除了 vptr,你可以说
-fsanitize=undefined -fno-sanitize=vptr
以下测试用例,从真实世界的应用程序中减少,无法 link -fsanitize=undefined
(使用 GCC 6.1.1),但 link 没有它也很好。谁能告诉我为什么?
似乎与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
我认为 -fsanitize=undefined
是一个转移话题。
您只是在导出 class 的成员函数。为了同时导出其元数据(如其类型信息和潜在的 v-table 指针),您需要导出 class.
试试这个
class EXPORT MyObject : public QObject
{
public:
MyObject (QObject * parent = nullptr);
~MyObject ();
void myMethod ();
};
那么您应该不需要标记各个成员函数。
所问实际问题的答案是 -fsanitize=undefined
实际上是一组消毒剂,包括 vptr
消毒剂。
https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
vptr
sanitizer 被清楚地标记为需要 RTTI,其他答案已经描述了为什么它不可用。
对运行所有测试除了 vptr,你可以说
-fsanitize=undefined -fno-sanitize=vptr