现有基础设施和分析

本文档介绍了 Mozilla 如何进行静态分析:在 Phabricator 中提交时运行的 Firefox 特定和通用 llvm clang-tidy 检查,以及如何在本地运行它们。有关如何开发自己的静态分析检查的信息,请参阅 编写新的 Firefox 特定检查

有关代码风格检查,请参阅 代码风格检查文档

对于审查,请使用 #static-analysis-reviewers 审查组。在 #static-analysis:mozilla.org 上提问。

Clang-Tidy 静态分析

如前所述,我们当前的静态分析基础设施基于 clang-tidy。我们使用的检查器分为 3 类

  1. Firefox 特定检查器。它们检测不正确的 Gecko 编程模式,这些模式可能导致错误或安全问题。

  2. Clang-tidy 检查器。它们旨在建议更好的编程实践,并提高内存效率和性能。

  3. Clang-analyzer 检查器。这些检查更高级,例如,其中一些可以检测死代码或内存泄漏,但作为典型副作用,它们会产生误报。因此,我们目前已禁用它们,但将在不久的将来启用其中一些。

为了简化静态分析过程,我们专注于将此过程与 Phabricator 和 mach 集成。一些在自动扫描期间使用的检查器的列表可以在 此处 找到。

审查阶段的静态分析

我们创建了一个 TaskCluster 机器人,它在提交到 Phabricator 的每个补丁上运行 clang 静态分析。然后它会在审查平台上直接快速报告任何代码缺陷,从而防止不良补丁落地,直到所有缺陷都得到修复。目前,其反馈在补丁系列发布到审查平台后约 10 分钟内发布。

作为流程的一部分,各种代码风格检查作业也使用 try 执行。这也可以用于添加新作业,请参阅:Try 构建的分析器符号。可以在 phabricator 上 找到自动审查的示例。

./mach static-analysis

在所有 Firefox 构建平台上都支持 ./mach static-analysis 命令。在第一次运行时,它会自动安装其所有依赖项(例如 clang-tidy 可执行文件),位于 .mozbuild 文件夹中,因此非常易于使用。使用的资源由工具链工件 clang-tidy 目标提供。

这通过 mach static-analysis 命令使用,该命令具有以下参数

  • check - 使用从 ~/.mozbuild 安装的辅助工具运行检查。

  • --checks, -c - 在扫描期间启用的检查。默认情况下使用 yaml 文件中 启用的检查。

  • --fix, -f - 尝试自动修复检查器检测到的错误。根据检查器的不同,此选项可能不起作用。可在 clang-tidy 网站 上找到具有自动修复功能的检查器列表。

  • --header-filter, -h-f - 与要输出诊断的头文件名称匹配的正则表达式。始终显示每个翻译单元主文件中的诊断。

例如,我们通过 mach 对 dom/presentation/Presentation.cpp 运行静态分析,并使用 google-readability-braces-around-statements 检查和自动修复,我们将拥有

./mach static-analysis check --checks="-*, google-readability-braces-around-statements" --fix dom/presentation/Presentation.cpp

如果要使用自定义 clang-tidy 二进制文件,可以通过使用 mach static-analysisinstall 子命令来完成,但请注意,要使用的存档必须与工具链工件中的 clang-tidy 目录结构兼容。

./mach static-analysis install clang.tar.gz

回归测试

为了防止基于 clang-tidy 的静态分析出现回归,我们在自动化中创建了一个 任务。此任务在每次提交时运行,并启动一个集成到 mach 中的测试套件。

测试套件实现了以下功能

  • 下载必要的 clang-tidy 工件。

  • 读取 配置文件

  • 对于每个检查器,读取测试文件以及预期结果。测试和预期结果的示例可以在 测试文件中json 文件中 找到。

可以通过执行以下操作在本地运行此测试套件

./mach static-analysis autotest

如果我们只想测试特定检查器,例如 modernize-raw-string-literal,我们可以运行

./mach static-analysis autotest modernize-raw-string-literal

如果要添加新的检查器,我们需要生成预期的结果文件,方法如下

./mach static-analysis autotest modernize-raw-string-literal -d

构建时静态分析

如果要使用 Firefox Clang 插件(位于 /build/clang-plugin 中,并与 MOZ_CLANG_PLUGIN 以及 /mfbt/Attributes.h 中的属性相关联),只需在 mozconfig 中添加 --enable-clang-plugin!如果还希望获得会生成 warnings 作为诊断消息的实验性检查器,请添加 --enable-clang-plugin-alpha。这需要使用 Clang 构建 Firefox。

配置构建环境

在准备好 Clang 构建后,需要设置工具以使用它。桌面浏览器的完整工作 .mozconfig 为

. $topsrcdir/browser/config/mozconfig
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-ff-dbg

ac_add_options --enable-debug

尝试使用 ccache 很可能会导致编译失败。还需要避免优化构建,因为这些构建会修改宏,从而导致许多误报。

此时,Firefox 构建环境应已配置为通过 Clang 静态分析器编译!

执行扫描构建

仅仅像往常一样开始构建是不够的。相反,需要通过 Clang 实用程序脚本运行构建,该脚本将跟踪所有生成的分析并自动将其合并。

报告每天发布在 https://sylvestre.ledru.info/reports/fx-scan-build/ 上,许多报告的缺陷作为良好初学者 Bug 的来源。

该脚本是 scan-build。可以在 $clang_source/tools/scan-build/scan-build 中找到它。

尝试通过 scan-build 运行构建

$ cd /path/to/mozilla/source

# Blow away your object directory because incremental builds don't make sense
$ rm -rf obj-dir

# To start the build:
scan-build --show-description ./mach build -v

# The above should execute without any errors. However, it should take longer than
# normal because all compilation will be executing through Clang's static analyzer,
# which adds overhead.

如果一切正常,应该会看到一堆控制台输出,就像任何构建一样。

第一次运行 scan-build 时,在编译几个文件后按 CTRL+C。应该会看到类似以下的输出

scan-build: 3 bugs found.
scan-build: Run 'scan-view /Users/gps/tmp/mcsb/2011-12-15-3' to examine bug reports.

如果看到类似以下的消息

scan-build: Removing directory '/var/folders/s2/zc78dpsx2rz6cpc_21r9g5hr0000gn/T/scan-build-2011-12-15-1' because it contains no reports.

要么尚无静态分析结果可用,要么环境配置不正确。

默认情况下,scan-build 将结果写入伪临时位置中的文件夹。可以通过将 -o /path/to/output 参数传递给 scan-build 来控制结果的存放位置。

还可以运行 scan-build --help 以查看所有可用的选项。例如,可以选择性地启用和禁用各个分析器。

分析输出

构建完成后,scan-build 将生成一份报告,总结所有发现。这在输出目录中称为 index.html。可以运行 scan-view(来自 $clang_source/tools/scan-view/scan-view),如 scan-build's 输出所示;这仅仅启动了一个本地 HTTP 服务器。或者应该能够使用浏览器直接打开 index.html

误报

根据定义,静态分析器目前存在误报。其中很多是由于分析器难以跟踪各种预处理器宏中相对复杂的错误处理。