- 静态分析
- 代码质量
- 开发工具
【免费下载链接】infer
A static analyzer for Java, C, C++, and Objective-C
导读
infer debug是 Infer 静态分析器中面向分析与调试场景的命令行工具,用于打印 Infer 捕获与分析过程中的内部数据结构——包括全局类型环境(global type environment)、每个被捕获的过程(procedure,即函数或方法)的属性、摘要(summary)与静态调用图,以及捕获到的源文件清单及其类型环境。本文以inferv1.1.0 的 man 手册原文为骨架,结合仓库中infer debug的 OCaml 实现源码(InferCommandImplementation.ml)与选项定义(Config.ml),逐项讲解每个开关的作用、输出位置与典型使用场景。读完本文,你将能够熟练使用infer debug查看捕获结果、导出 JSON 摘要、输出 DOT 格式的调用图/CFG,并借助--procedures-filter、--select等参数高效定位特定过程或源文件。
命令概览与基本用法
infer debug的核心职责是打印 Infer 内部数据结构,它不执行分析,而是读取已有捕获(capture)与分析产物。其基本语法如下(来自 infer-debug.txt):
infer debug --global-tenv infer debug --procedures [options] infer debug --source-files [options]三个模式分别对应:
--global-tenv:打印全局类型环境(如果存在);--procedures:打印 Infer 捕获到的每个过程(函数/方法)的相关信息;--source-files:打印被捕获源文件的相关信息。
必须且至少传入上述三个开关之一,否则命令会直接报错退出。这一约束在源码中有明确体现:infer/src/integration/InferCommandImplementation.ml中的debug ()函数开头即检查:
if not Config.(global_tenv || procedures || source_files || Option.is_some export_textual) then L.die UserError "Expected at least one of '--global-tenv', '--procedures', '--source-files' or \ '--export-textual'.@\n"即,infer debug要求至少传入--global-tenv、--procedures、--source-files或--export-textual之一,否则抛出UserError。注意这里的--export-textual也属于可用入口(详见下文"导出 textual SIL"小节)。
通用选项
以下选项对所有模式均可用:
| 选项 | 说明 |
|---|---|
--help | 显示本手册(帮助信息) |
--help-format { auto \| groff \| pager \| plain } | 以指定格式显示帮助。auto模式在环境变量TERM为dumb或未定义时使用plain格式,否则使用pager格式 |
--help-full | 显示包含全部内部选项(INTERNAL OPTIONS 一节)的完整手册 |
--preanalysis-html | 是否启用预处理阶段(preanalysis)的 HTML 节点打印,默认关闭(false),以便专注于已启用分析的调试输出;反向开关为--no-preanalysis-html |
--select (N\|all) | 选择编号为 N 的选项或全部选项。省略该参数时,会以交互方式提示输入(详见下文"交互式选择") |
这些选项定义于 Config.ml,并通过CLOpt.mk_bool等构造器注册,每个布尔开关都有对应的--no-<name>反向形式。
调试全局类型环境(DEBUG GLOBAL TYPE ENVIRONMENT)
--global-tenv
激活后打印全局类型环境(global type environment)。反向开关:--no-global-tenv。
全局类型环境是 Infer 在捕获阶段构建的、描述程序中所有可见类型(类、结构体、类型别名等)的全局映射。在源码实现中(InferCommandImplementation.ml 第 17-22 行),当Config.global_tenv为真时:
match Tenv.Global.load () with | None -> L.result "No global type environment was found.@." | Some tenv -> L.result "Global type environment:@\n@[<v>%a@]" Tenv.pp tenv即从磁盘加载全局类型环境:若不存在则输出No global type environment was found.,否则以Tenv.pp的可读文本形式打印整个类型环境。该数据由Tenv.Global模块管理,通常在分析前由前端(如 Clang 前端)写入结果目录。
调试过程(DEBUG PROCEDURES)
--procedures模式是infer debug最常用的入口,它围绕"过程"(procedure,即函数/方法)提供多种信息视图。相关开关定义在 Config.ml 中,并归类到manual_debug_procedures = "DEBUG PROCEDURES"帮助分组。
基础信息开关
| 选项 | 默认值 | 说明 |
|---|---|---|
--procedures | 关 | 打印 Infer 发现的函数与方法(过程的名称等基础信息) |
--procedures-name | 关 | 在--procedures的输出中包含过程名称 |
--procedures-attributes | 关 | 在--procedures的输出中打印每个过程的属性(attributes),如参数、返回类型、访问权限等 |
--procedures-callees | 关 | 在--procedures的输出中打印每个过程的静态被调用者(callees) |
--procedures-source-file | 开 | 在--procedures的输出中包含过程定义或声明所在的源文件(反向开关--no-procedures-source-file) |
--procedures-definedness | 开 | 在--procedures的输出中显示过程的"定义性":即过程定义是否被找到、是否仅有声明,或是否为自动生成的 Objective-C accessor(反向开关--no-procedures-definedness) |
以基础打印为例,源码中通过Config.Procedures.pp_all一次性组合上述各开关的输出:
L.result "%a" Config.( Procedures.pp_all ~filter ~proc_name:procedures_name ~defined:procedures_definedness ~source_file:procedures_source_file ~proc_attributes:procedures_attributes ~proc_cfg:procedures_cfg ~callees:procedures_callees ) ()过滤:--procedures-filter filter
与--procedures配合使用时,只打印匹配指定过滤器的过程。过滤器格式为path_pattern:procedure_name,其中模式按OCaml Str 正则表达式解释。例如,只保留名为foo的方法,可以使用".*:foo",或者简写为"foo"。
过滤器的实现位于 InferCommandImplementation.ml(第 24 行),通过Lazy.force Filtering.procedures_filter惰性求值得到,并贯穿整个--procedures分支:无论是打印摘要、导出 JSON 还是生成调用图,filter都会被传入Procedures.get_all ~filter。
摘要导出:文本与 JSON
| 选项 | 说明 |
|---|---|
--procedures-summary | 打印每个过程的摘要(summary)。摘要记录了分析器对每个过程的分析结论(如内存泄漏、空指针等抽象状态)。反向开关--no-procedures-summary |
--procedures-summary-json | 将每个过程的摘要以 JSON 形式输出。反向开关--no-procedures-summary-json |
--procedures-summary-skip-empty | 完全跳过没有摘要的过程。在分析大型项目的一小部分时非常有用(常与--procedures-summary或--procedures-summary-json配合使用,也常与--changed-files-index联用)。反向开关--no-procedures-summary-skip-empty |
--dump-json-summaries | 直接将每个已分析过程的 JSON 摘要导出到<output-dir>/all_summaries.json(即<results-dir>/all_summaries.json)。反向开关--no-dump-json-summaries |
--dump-json-specialized-call-graph | 直接将特化调用图(specialized call graph)的 JSON 导出到<output-dir>/specialized_call_graph.json。反向开关--no-dump-json-specialized-call-graph |
在实现层面(InferCommandImplementation.ml 第 32-84 行),当--procedures-summary或--procedures-summary-json被激活时,逻辑按以下优先级展开:
- 若
--dump-json-summaries开启,则通过Summary.OnDisk.get读取每个过程的摘要,以Summary.yojson_of_t序列化为 JSON 列表,写入Config.results_dir下的all_summaries.json; - 否则若
--dump-json-specialized-call-graph开启,则基于每个过程摘要的pulsepayload,通过PulseSpecializedCallGraph.JsonBuilder构建特化调用图,写入specialized_call_graph.json(输出前会按Procname.compare排序以保证确定性); - 否则进入交互选择流程(见下文),再按
--procedures-summary-json决定输出 JSON 到 stdout 还是以Summary.pp_text打印可读文本。
--procedures-summary-skip-empty在源码中体现为过滤器组合(第 26-31 行):
let filter source_file proc_name = procedures_filter source_file proc_name && if Config.procedures_summary_skip_empty then Option.is_some (summary_of proc_name) else true即启用后,没有摘要的过程会被直接过滤掉。
调用图与 CFG 的 DOT 输出
| 选项 | 输出文件 | 说明 |
|---|---|---|
--procedures-call-graph | infer-out/captured/syntactic-call-graph.dot | 输出语法调用图(syntactic call graph)的 dotty 文件。该图从所有被捕获过程出发(或由--changed-files-index决定的过程集合)可达。反向开关--no-procedures-call-graph |
--procedures-cfg | infer-out/captured/<file_name>/<proc_name>.dot | 为--procedures输出中的每个过程输出控制流图(CFG)的 dotty 文件。反向开关--no-procedures-cfg |
在实现中(InferCommandImplementation.ml 第 85-93 行),--procedures-call-graph优先读取配置文件(SourceFile.read_config_files_to_analyze)确定的文件集合,否则使用全部源文件,然后通过SyntacticCallGraph.build_from_sources构建并以to_dotty写出。
而--procedures-cfg的实现与--source-files-cfg共享一套逻辑(第 127-140 行):遍历源文件、为每个过程中的每个过程加载Procdesc(过程描述,即 CFG),最后调用DotCfg.emit_frontend_cfg生成 DOT 文件,并打印提示CFGs written in %s/*/%s。
交互式选择:--select (N|all)
当同时开启了摘要输出但未指定--dump-json-*时,infer debug --procedures会进入交互选择流程。--select用于指定选择编号为 N 的选项或all;若省略,则在终端中交互提示输入。该逻辑实现在 Procedures.ml 的select_proc_names_interactive中:
- 若没有匹配的过程,直接打印
No procedures found; - 若
--select N中 N 超出过程总数,抛出UserError(Cannot select result #%d out of only %d procedures); - 若仅有一个匹配过程,自动选中它并打印
Selected proc name: ...; - 若
--select all,选中全部; - 若
--select N,只选中第 N 个; - 若省略
--select,则列出全部过程的编号(0: <proc_name>格式),提示输入一个编号、a(全部)或q(退出)。
调试源文件(DEBUG SOURCE FILES)
--source-files模式围绕被捕获的源文件提供信息,相关开关归类于manual_debug_source_files = "DEBUG SOURCE FILES"。
基础信息开关
| 选项 | 默认值 | 说明 |
|---|---|---|
--source-files | 关 | 打印 Infer 发现的源文件 |
--source-files-freshly-captured | 关 | 在--source-files输出中打印该源文件是否在最近一次捕获阶段中被捕获(freshly captured) |
--source-files-procedure-names | 关 | 在--source-files输出中打印每个源文件包含的过程名称 |
--source-files-type-environment | 关 | 在--source-files输出中打印每个源文件的类型环境 |
--source-files-filter filter | — | 与--source-files配合时只打印匹配的源文件。过滤器是应匹配文件路径的模式,按 OCaml Str 正则表达式解释 |
基础输出的实现位于 InferCommandImplementation.ml 第 121-126 行,通过SourceFiles.pp_all结合~type_environment、~procedure_names、~freshly_captured三个开关打印,过滤器来自Lazy.force Filtering.source_files_filter。
文件级调用图与分区
| 选项 | 输出/行为 | 说明 |
|---|---|---|
--source-files-call-graph | infer-out/captured/file-call-graph.dot | 输出基于文件的语法调用图:所有被捕获过程(含已知编译单元)按文件聚合的调用关系图。反向开关--no-source-files-call-graph |
--source-files-call-graph-partition int | infer-out/captured/workerXX.idx | 利用静态调用图信息将被捕获源文件集合划分为指定数量的分区(partition),生成的文件列表位于infer-out/captured/workerXX.idx。不设置该选项则跳过分区。该功能用于分布式分析 |
--source-files-cfg | infer-out/captured/... | 为--source-files输出中的每个源文件输出控制流图(dotty 文件)。反向开关--no-source-files-cfg |
实现上(第 101-105 行),三个开关互斥分支:--source-files-call-graph直接调用SourceFileGraph.to_dotty "file-call-graph.dot";--source-files-call-graph-partition则调用SourceFileGraph.partition_source_file_call_graph ~n_workers做分区。
捕获数据库操作:提取与补全
以下两个开关用于操作捕获数据库(capture database),是增量/分布式分析流程中的关键工具:
--extract-capture-from path:提供包含捕获数据库的 Infer results 目录路径。配合必须使用的--changed-files-index(提供文件列表),在--results-dir指定的位置创建一个只包含这些文件相关产物的新捕获数据库。源码第 106-113 行中,若未提供--changed-files-index会抛出UserError:When extracting a capture database, --changed-files-index must be specified.,随后调用CaptureManipulation.extract。--complete-capture-from path:提供包含捕获数据库的 Infer results 目录路径。根据结果目录中的missing-*文件,将--results-dir指定的捕获数据库从输入数据库补全(complete)。命令的退出码等于添加到捕获数据库中的行数。实现位于第 114-119 行,通过CaptureManipulation.complete完成,并输出MODIFIED或UNMODIFIED。
导出 textual SIL:--export-textual string
将捕获数据库(capture.db)中的 textual SIL 导出到指定输出目录:
- 每个源文件对应一个
.sil文件; - 同时生成
manifest.json,将源文件路径映射到其.sil文件名; - 前提条件:需要先前使用
--dump-textual或--store-textual进行过捕获。
源码实现(第 142-160 行起)中,导出时会先IUnix.mkdir_p创建输出目录,按SourceFile.compare对源文件排序以保证输出顺序确定,并使用used_names表处理文件名冲突:例如src/foo.c与lib/foo.c的 basename 都是foo,后者会被命名为foo_1.sil。manifest.json会记录每个源文件(相对项目根目录)到其.sil文件名及过程名称列表的映射。该功能在debug ()的入口校验中被视为可独立使用的模式之一(见上文源码第 12 行)。
运行环境与配置文件
环境变量
infer debug遵循infer(1)手册中定义的环境变量约定:
| 变量 | 说明 |
|---|---|
INFER_ARGS | 向所有 Infer 命令注入额外的命令行参数 |
INFERCONFIG | 指定额外的配置文件路径 |
INFER_STRICT_MODE | 启用严格模式(strict mode),开启更严格的参数与使用检查 |
配置文件
infer debug同样支持.inferconfig配置文件(位于项目根目录),其规则与infer(1)的 FILES 一节一致:命令行参数优先级高于配置文件。因此,常用调试参数(如--procedures-filter、--results-dir)也可以写入.inferconfig统一管理。
典型使用场景速查
查看某个文件里所有过程及其摘要
infer debug --procedures --procedures-filter 'path/to/file.c:.*' --procedures-summary导出全部过程的 JSON 摘要供二次分析
infer debug --procedures --dump-json-summaries # 结果写入 <results-dir>/all_summaries.json输出语法调用图与每个过程的 CFG
infer debug --procedures --procedures-call-graph --procedures-cfg # infer-out/captured/syntactic-call-graph.dot # infer-out/captured/<file_name>/<proc_name>.dot为分布式分析切分源文件
infer debug --source-files --source-files-call-graph-partition 8 # 生成 infer-out/captured/worker00.idx ... worker07.idx从已有捕获库中提取子集或补全捕获库
infer debug --source-files --extract-capture-from /path/to/old-results \ --changed-files-index changed-files.txt --results-dir infer-out-new infer debug --source-files --complete-capture-from /path/to/old-results导出 textual SIL 供外部消费
infer capture --dump-textual . # 捕获时同时存储 textual SIL infer debug --export-textual /tmp/textual-sil相关命令
infer debug的输出(摘要、调用图、类型环境)与以下命令/文档互补:
infer explore(infer-explore.txt):在交互界面中浏览分析结果与错误轨迹;infer report(infer-report.txt):以文本/JSON/CSV 等格式输出分析报告。
三者配合使用,可以覆盖"调试数据结构 → 探索分析结果 → 生成正式报告"的完整分析工作流。
小结
infer debug是深入 Infer 内部机制的第一入口:它把捕获阶段产生的类型环境、过程属性、分析摘要、调用图、CFG 乃至 textual SIL 全部以可读或机器可解析(JSON/DOT)的形式暴露出来。其全部选项与行为均可在 infer/man/man1/infer-debug.txt(对应帮助页面 man-infer-debug.md)中查阅,实现细节位于 InferCommandImplementation.ml 的debug ()函数,选项定义位于 Config.ml。建议读者结合自己的捕获产物实际运行以上命令组合,以直观理解 Infer 的数据流。
- 静态分析
- 代码质量
- 开发工具
【免费下载链接】infer
A static analyzer for Java, C, C++, and Objective-C
相关推荐
Infer Debug 命令完全指南:深入探查 infer 内部数据结构
Infer Debug 命令完全指南:深入探查 infer 内部数据结构 本篇指南围绕静态分析器 Infer 的 infer debug 子命令展开,讲解如何借
静态分析代码质量开发工具Infer Debug 命令完全指南:深入剖析 infer 内部数据结构与捕获产物
Infer Debug 命令完全指南:深入剖析 infer 内部数据结构与捕获产物 导读 infer debug 是 Facebook Infer 静态分析器(
静态分析代码质量开发工具SumatraPDF 命令行工具指南:用 `sumatrapdf-tool info` 透视 PDF 内部资源结构
SumatraPDF 命令行工具指南:用 sumatrapdf tool info 透视 PDF 内部资源结构 本文基于 SumatraPDF 官方文档 Too
桌面应用文档
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考