Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does -fsanitize=undefined cause "undefined reference to typeinfo"?

The following test-case, reduced from a real-world application, fails to link with -fsanitize=undefined (using GCC 6.1.1) but links fine without it. Can anyone tell me why?

It seems to have something to do with the combination of Qt/QObject, -fvisibility=hidden, and -fsanitize=undefined, but exactly where the problem lies is beyond me.

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 ();
}

Build steps:

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

Build output (from the final step):

/tmp/ccY7PHv4.o:(.data.rel+0x18): undefined reference to `typeinfo for MyObject'
collect2: error: ld returned 1 exit status
like image 835
John Lindgren Avatar asked May 21 '16 03:05

John Lindgren


2 Answers

The answer to the actual question as asked is that -fsanitize=undefined is actually a collection of sanitizers including the vptr sanitizer.

https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html

The vptr sanitizer is clearly marked as requiring RTTI, which other answers have described why it's not available.

To run all the tests except vptr, you can say

-fsanitize=undefined -fno-sanitize=vptr
like image 140
xaxxon Avatar answered Sep 16 '22 17:09

xaxxon


I think the -fsanitize=undefined is a red herring.

You are only exporting the member functions of that class. In order to also export its metadata (like its typeinfo and potential v-table pointer) you need to export the class.

Try this

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

    void myMethod ();
};

Then you should not need to mark up the individual member functions.

like image 22
Arvid Avatar answered Sep 19 '22 17:09

Arvid