首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++ UBSAN生成带有派生对象的假阳性

C++ UBSAN生成带有派生对象的假阳性
EN

Stack Overflow用户
提问于 2019-07-31 15:57:40
回答 1查看 3.4K关注 0票数 11

我想使用UBSAN (未定义的行为消毒剂),但发现它完全没有价值,因为它向许多错误的阳性报告。

一个简单的std::make_shared<int>(42);就足以触发类似的警告

地址0x00000236de70中的成员访问权限,该地址不指向“_Sp_counted_base”类型的对象

将此示例简化为MWE显示,基类和继承的问题更为普遍:

示例:

代码语言:javascript
复制
struct Foo{
    int f(){ return g(); }
    virtual int g() = 0;
};

struct Bar: Foo{
    int g(){ return 42; }
};

int main(){
    auto f = new Bar();
    return f->g();
}

-fsanitize=undefined和watch编译

example.cpp:15:16:运行时错误:对地址0x000000726e70的成员调用,它没有指向'Bar‘类型的对象 0x000000726e70:注意:对象具有无效的vptr

https://godbolt.org/z/0UiVtu

这些简单的个案,如何处理得不好呢?我错过什么了吗?如何正确地使用UBSAN检查我的代码?(这几乎不需要假阳性)

编辑:由于MWE似乎只适用于戈德螺栓,原始代码如下所示:

代码语言:javascript
复制
#include <boost/iostreams/device/mapped_file.hpp>
#include <boost/iostreams/stream.hpp>
using MMStream = boost::iostreams::stream<boost::iostreams::mapped_file_source>;

int main(){
  MMStream stream;
  stream.open("a.out");
  return !stream;
}

使用clang++-8 -fsanitize=undefined -fvisibility=hidden -I /opt/boost_1_64_0/include/ test.cpp /opt/boost_1_64_0/lib/libboost_iostreams.so编译并运行,这将导致以下错误

运行时错误:对地址0x00000126ef30的成员调用,它没有指向“boost::detail::sp_counted_base”类型的对象

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-08-01 07:44:38

试着在评论后自己回答,并创建另一个MWE。

TLDR:使用-fvisibility=hidden编译时,确保所有包含虚拟函数的类都被导出

考虑一个共享库Foo

foo.h

代码语言:javascript
复制
#define EXPORT __attribute__((visibility("default")))

struct Foo{
    virtual int g() = 0;
};

struct Bar: Foo{
    int g(){ return 42; }
};

EXPORT Foo* create();

foo.cpp #包括"foo.h“

代码语言:javascript
复制
Foo* create(){
  return new Bar();
}

clang++-8 foo.cpp -shared -fPIC -o foo.so编译

以及使用虚拟函数(但使用-fvisibility )链接的可执行文件

main.cpp:

代码语言:javascript
复制
#include "foo.h"

int main(){
  Foo* f  = create();
  return f->g() != 42;
}

clang++-8 -fsanitize=undefined -fvisibility=hidden main.cpp foo.so编译

这将报告

运行时错误:对地址0x00000290cea0的成员调用,它没有指向“Foo”类型的对象

这与bug.cgi?id=39191中描述的错误相同(谢谢@Nikita )

摘要:由于fvisibility=hidden没有导出符号(函数,没有使用属性__attribute__((visibility("default")))修饰的类在不同的DSO中使用时被认为是不同的)(例如可执行库和共享库)。因此,共享库中的基类Foo和可执行文件是不同的(它们有不同的vtable ),UBSAN检测到:可执行文件“期望”Exe::Foo的vtable对象,但得到Library::Foo

在boost的情况下,类sp_counted_base是罪魁祸首,因为它直到Boost 1.69才被导出,这增加了BOOST_SYMBOL_EXPORT,因此切换到Boost 1.69+解决了这个问题。

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57294792

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档