我试图在一个项目中使用 UBSAN,但遇到了一个似乎无法解决的问题:该项目使用了一个通过共享库实现的插件系统。也就是说,每个插件都提供了一个工厂方法,该方法返回一个带有插件特定派生类的抽象类的实例。然后该项目遍历文件夹中的所有共享库,使用 打开它们dlopen
,通过获取工厂方法dlsym
并创建插件实例,然后使用该实例。
然而,在使用任何接口方法 UBSAN 抛出member call on address 0x... which does not point to an object of type '...'
MWE:
foo.h
struct Foo{
virtual int g() = 0;
};
extern "C" Foo* create();
foo.cpp
#include "foo.h"
struct Bar: Foo{
int g(){ return 42; }
};
Foo* create(){
return new Bar();
}
主文件
#include "foo.h"
#include <dlfcn.h>
#include <cassert>
int main(){
void* h = dlopen("libfoo.so", RTLD_GLOBAL | RTLD_NOW);
assert(h);
void* c = dlsym(h, "create");
assert(c);
using create_t = Foo*();
Foo* f = reinterpret_cast<create_t*>(c)();
return f->g() != 42;
}
编译:
g++ -shared -fPIC -o libfoo.so foo.cpp
g++ -fsanitize=vptr main.cpp -ldl
./a.out
https://whatofhow.wordpress.com/2015/03/17/odr-rtti-dso解释说,这是由于共享库中的 RTTI 信息和二进制文件不同。
一个非常相似的问题发生了,当您在共享库中导出一个函数时,将其导入dlsym
并尝试调用它。结果将是call to function <...> through pointer to incorrect function type '<...>'
for -fsanitize=function
clang。
有没有办法解决这个问题?我没有使用 Clang 或玩,-fvisibility
所以不知道在这里做什么。