Предупреждение Clang UBsan об экспортированном виртуальном классе для общего объекта

Я пытаюсь применить UBSan Clang на моем приложении, которое интенсивно использует dlopen / dlsym. Однако, когда я применяю UBSan, появлялись некоторые предупреждения, которые я не мог полностью понять.

Пример кода с одним заголовком / двумя файлами.

foo.h

#ifndef FOO_H
#define FOO_H

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

class EXPORT Foo {
public:
virtual ~Foo() noexcept = 0;
virtual int bar(int value) = 0;
};

inline Foo::~Foo() noexcept {}

#endif // FOO_H

foo.cpp

#include "Foo.h"#include <cstddef>

#define EXPORT_C extern "C" EXPORT

EXPORT_C bool NewFoo(Foo** foo) noexcept;
EXPORT_C void DeleteFoo(Foo* foo) noexcept;

class EXPORT FooImpl: public Foo {
public:
FooImpl();
virtual ~FooImpl() noexcept;

virtual int bar(int value);
private:
int val_;
};

EXPORT
FooImpl::FooImpl(): val_(1) {};

EXPORT
FooImpl::~FooImpl() noexcept {};

EXPORT
int FooImpl::bar(int value) {
return value + val_;
}

EXPORT_C
bool NewFoo(Foo** foo) noexcept {
if (foo == NULL) {
return false;
}

try {
*foo = new FooImpl();
}
catch(...) {
return false;
}
return true;
}

EXPORT_C
void DeleteFoo(Foo* foo) noexcept {
delete foo;
}

test.cpp

#include "Foo.h"#include <iostream>
#include <unistd.h>
#include <dlfcn.h>

using fNewFoo_t = bool(*)(Foo**);
using fDeleteFoo_t = void(*)(Foo*);

int main() {
Foo* foo = NULL;

void* handle = dlopen("./libfoo.so", RTLD_LAZY);
if (handle == NULL) {
fprintf(stderr, "dlopen: %s\n", dlerror());
exit(EXIT_FAILURE);
}

fNewFoo_t fNewFoo = reinterpret_cast<fNewFoo_t>(dlsym(handle, "NewFoo"));
fDeleteFoo_t fDeleteFoo = reinterpret_cast<fDeleteFoo_t>(dlsym(handle, "DeleteFoo"));

if ((fNewFoo == NULL) || (fDeleteFoo == NULL)) {
fprintf(stderr, "dlsym: %s\n", dlerror());
dlclose(handle);
exit(EXIT_FAILURE);
}

if (!fNewFoo(&foo)) {
fprintf(stderr, "NewFoo Failed\n");
dlclose(handle);
exit(EXIT_FAILURE);
}

int i = 0;
for (int j = 0; j < 3; j++) {
i = foo->bar(i);
std::cout << i << "\n";
}
fDeleteFoo(foo);
dlclose(handle);

return 0;
}

строить & Бежать

$ clang++ -fsanitize=undefined -g -fPIC -fvisibility=internal -std=gnu++11 -shared -o libfoo.so Foo.cpp
$ clang++ -fsanitize=undefined -g -std=gnu++11 -o test test.cpp -ldl
$ ./test
test.cpp:27:10: runtime error: call to function NewFoo through pointer to incorrect function type 'bool (*)(Foo **)'
Foo.cpp:31: note: NewFoo defined here
test.cpp:35:18: runtime error: member call on address 0x000001f312b0 which does not point to an object of type 'Foo'
0x000001f312b0: note: object is of type 'FooImpl'
00 00 00 00  20 ad f2 1f 0e 7f 00 00  01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  21 00 00 00
^~~~~~~~~~~~~~~~~~~~~~~
vptr for 'FooImpl'
1
2
3
test.cpp:38:5: runtime error: call to function DeleteFoo through pointer to incorrect function type 'void (*)(Foo *)'
Foo.cpp:46: note: DeleteFoo defined here

Первая и третья ошибка очевидна: я использовал reinterpret_cast, и UBSan не может понять, откуда появился такой указатель. Тем не менее, я не могу понять, почему Fooа также FooImplОтношения наследования не применяются при работе с vptr. Может ли это быть реальная проблема или ошибка UBSan (или ограничения?)

0

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]