【问题标题】:Make clang's Memory Sanitizer report unitialised variable use without it deciding branching让 clang 的 Memory Sanitizer 在不决定分支的情况下报告统一变量的使用
【发布时间】:2018-12-13 03:11:59
【问题描述】:

我正在试验 Clang 6.0 的 Memory Sanitizer(MSan)。 代码用

编译
clang++ memsans.cpp -std=c++14 -o memsans -g -fsanitize=memory -fno-omit-frame-pointer -Weverything

在 Ubuntu 18.04 上。根据 MSan documentation

它可以容忍复制未初始化的内存,而且也很简单 逻辑和算术运算。一般来说,MemorySanitizer 静默跟踪未初始化数据在内存中的传播,以及 在采用(或不采用)代码分支时报告警告,具体取决于 在一个未初始化的值上。

所以下面的代码不会产生任何错误

#include <iostream>

class Test {
public:
    int x;
};

int main() {
    Test t;
    std::cout << t.x;
    std::cout << std::endl;
    return 0;
}

但这会

#include <iostream>

class Test {
public:
    int x;
};

int main() {
    Test t;
    if(t.x) {
        std::cout << t.x;
    }
    std::cout << std::endl;
    return 0;
}

理想情况下,人们希望这两个代码示例都产生某种错误,因为两者都“使用”了一个未初始化的变量,即第一个正在打印它。这段代码是一个小的测试代码,因此第一个代码中的错误很明显,但是如果它是一个带有类似错误的大型代码库,MSan 会完全错过这个。是否有任何 hack 可以强制 MSan 也报告此类错误?

【问题讨论】:

  • 请注意,一些编译器可能会捕捉到未初始化变量的使用:GCC (godbolt.org/g/YXk4z1) 和 MSVC (godbolt.org/g/UPmBK6)。
  • 我有点惊讶第一个示例没有产生错误,因为itoa() 应该需要对数据进行一些分支才能知道何时停止。 (也许这是在 libc++ 的预编译部分执行的?)
  • @Acorn 使用像 MSan 这样的工具,我期待运行时调试,您的建议是正确的,但它是编译时检查。
  • 好像是个bug,你可以记录一下
  • 将尽可能多的工作(包括验证)预先加载到编译时是 C++ 最基本的方面之一。像 MSan 这样的工具是很好的安全网,但它们绝不应该是您发现错误的主要手段。 (我认为您的问题仍然有效,只是回复您对编译与运行时检查的看法)

标签: c++ memory clang llvm address-sanitizer


【解决方案1】:

听起来您的 C++ 库不是用 MSan 构建的。与 ASan 和 UBSan 不同,MSan 要求整个程序在构建时启用了 msan。可以把它想象成拥有不同的 ABI,您不应该链接使用不同 msan 设置构建的两个程序。一个例外是 libc,msan 为其添加了“拦截器”以使其工作。

如果您编写自己的代码并希望通过报告错误来与 msan 集成,而 msan 通常不会(例如,在制作副本但您知道需要初始化数据的函数中),那么您可以使用__msan_check_mem_is_initialized 来自 msan_interface.h 文件:https://github.com/llvm-mirror/compiler-rt/blob/master/include/sanitizer/msan_interface.h

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多