内存/地址Sanitizer与Valgrind的比较

53

我想要一些诊断 use-after-free 漏洞和未初始化漏洞的工具。我正在考虑使用 Sanitizer(内存和/或地址)和 Valgrind。但我对它们的优缺点知之甚少。有人能告诉我 Sanitizer 和 Valgrind 的主要特点、区别以及优缺点吗?

编辑:我找到了一些比较,例如:Valgrind 使用动态二进制插装(DBI),而 Sanitizer 使用编译时插装(CTI)。Valgrind 会使程序变得非常慢(20倍),而 Sanitizer 运行速度比 Valgrind 快得多(2倍)。如果有人可以给我更多需要考虑的重要因素,那将是一个很大的帮助。

2个回答

59

我觉得你会发现这个wiki很有用。

简而言之,内存安全工具的主要优势有:

  • 更小的CPU开销(Lsan几乎是免费的,UBsan/Isan是1.25倍,Asan和Msan在计算密集型任务中是2-4倍,在GUI中是1.05-1.1倍,Tsan是5-15倍)
  • 更广泛的错误检测范围(堆栈和全局溢出,返回后/作用域后的使用)
  • 完全支持多线程应用程序(Valgrind对多线程的支持简直是个笑话)
  • 更小的内存开销(Asan最多为2倍,Msan最多为3倍,Tsan最多为10倍,远远优于Valgrind)

缺点是:

  • 更复杂的集成(您需要教导您的构建系统理解Asan,并且有时需要解决Asan本身的限制/错误,您还需要使用相对较新的编译器)
  • 目前MemorySanitizer不容易使用,因为它要求用户重新构建所有依赖项,包括所有标准库,如libc++;这意味着普通用户只能使用Valgrind来检测未初始化错误
  • 通常无法将不同的sanitizers组合在一起(唯一支持的组合是Asan+UBsan+Lsan),这意味着您需要进行单独的QA运行来捕捉所有类型的错误

5
请注意,Valgrind可以正确支持多线程应用程序。但是,每次只有一个线程在执行(因此,在Valgrind下运行的应用程序实际上就像在单个核心上运行一样)。 - phd
1
@phd 是的,这就是我的意思,它们实际上是单线程的。在许多情况下,这会导致性能问题。 - yugr
@kayas 关于组合使用Sanitizer - 唯一支持的组合是ASan+UBSan+LSan。通常人们会独立地在每个Sanitizer下运行他们的软件。这是一个重要的缺点,我会将其添加到列表中。 - yugr
线程污点分析器在clang 12.0.0版本中也适用于Mac OSX。https://clang.llvm.org/docs/ThreadSanitizer.html - Leo
@Leo 对的,但问题是针对与内存相关的净化器。 - yugr
显示剩余6条评论

4
一大区别在于LLVM内置的内存线程检测器会隐式映射大量地址空间(例如,在x86_64环境中通过调用mmap(X, Y, 0, MAP_NORESERVE|MAP_ANONYMOUS|MAP_FIXED|MAP_PRIVATE, -1, 0)映射数千兆字节的地址空间)。尽管它们不一定分配该内存,但是映射可能会影响具有限制性环境的运行(例如,对于ulimit值设置合理的环境)。

1
“Havoc” 可能有点过了。应用程序只会在启动时中止,并显示易于通过 Google 搜索的错误消息,建议用户重置 ulimit - yugr
@yugr 更改 ulimit 有时比说起来容易(特别是在分布式测试环境中,该环境不在您的直接控制之下);此外,还有其他(也许是病态的)情况,其中一个想要在 valgrind 下运行经过消毒仪器检测的二进制文件,在这种情况下,测试工具包将看到对此未使用的空间的引用作为实际使用(因此需要为其分配会计空间)。更不用说看到 topps 显示进程大小为 124.2t 也是令人不安/困惑的... - jhfrontz
分布式测试环境对于Valgrind或任何其他动态工具来说始终是非常棘手的(是的,我尝试过所有这些工具),因此我不确定sanitizer比其他工具更糟糕。经过消毒的应用程序无法在valgrind下运行(存在一些内存冲突)。 - yugr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接