Infer `debug` 子命令完全指南:透视内部数据结构、过程摘要与调用图
2026/9/24 1:43:22 网站建设 项目流程
  • 静态分析
  • 代码质量
  • 开发工具

【免费下载链接】infer

A static analyzer for Java, C, C++, and Objective-C

项目地址:https://gitcode.com/gh_mirrors/infer/infer
点击查看免费下载

导读

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模式在环境变量TERMdumb或未定义时使用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被激活时,逻辑按以下优先级展开:

  1. --dump-json-summaries开启,则通过Summary.OnDisk.get读取每个过程的摘要,以Summary.yojson_of_t序列化为 JSON 列表,写入Config.results_dir下的all_summaries.json
  2. 否则若--dump-json-specialized-call-graph开启,则基于每个过程摘要的pulsepayload,通过PulseSpecializedCallGraph.JsonBuilder构建特化调用图,写入specialized_call_graph.json(输出前会按Procname.compare排序以保证确定性);
  3. 否则进入交互选择流程(见下文),再按--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-graphinfer-out/captured/syntactic-call-graph.dot输出语法调用图(syntactic call graph)的 dotty 文件。该图从所有被捕获过程出发(或由--changed-files-index决定的过程集合)可达。反向开关--no-procedures-call-graph
--procedures-cfginfer-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 超出过程总数,抛出UserErrorCannot 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-graphinfer-out/captured/file-call-graph.dot输出基于文件的语法调用图:所有被捕获过程(含已知编译单元)按文件聚合的调用关系图。反向开关--no-source-files-call-graph
--source-files-call-graph-partition intinfer-out/captured/workerXX.idx利用静态调用图信息将被捕获源文件集合划分为指定数量的分区(partition),生成的文件列表位于infer-out/captured/workerXX.idx。不设置该选项则跳过分区。该功能用于分布式分析
--source-files-cfginfer-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会抛出UserErrorWhen 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完成,并输出MODIFIEDUNMODIFIED

导出 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.clib/foo.c的 basename 都是foo,后者会被命名为foo_1.silmanifest.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

项目地址:https://gitcode.com/gh_mirrors/infer/infer
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询