uber-go/nilaway

GitHub: uber-go/nilaway

NilAway 是一款 Go 语言的静态分析工具,通过在编译时追踪跨函数和跨包的 nil 流来检测并预防潜在的 nil panic。

Stars: 3829 | Forks: 92

# NilAway [![GoDoc](https://pkg.go.dev/badge/go.uber.org/nilaway.svg)][doc] [![Build Status](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/1a943c6426100536.svg)][ci] [![Coverage Status](https://codecov.io/gh/uber-go/nilaway/branch/main/graph/badge.svg)][cov] NilAway 是一个静态分析工具,旨在通过在编译时而非运行时捕获 nil panic,来帮助开发者避免在生产环境中发生此类错误。NilAway 类似于标准的 [nilness analyzer](https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/nilness),但是,它采用了更加复杂和强大的静态分析技术,来跟踪包内以及_跨_包的 nil 流,并报告错误,为用户提供 nilness 流以便于调试。 NilAway 具备三个使其脱颖而出的关键特性: - **完全自动化**:NilAway 配备了推理引擎,因此除了标准的 Go 代码外,它_不_需要开发者提供任何额外信息(例如注解)。 - **速度快**:我们将 NilAway 设计得快速且可扩展,使其适用于大型代码库。在我们的测试中,我们发现启用 NilAway 带来的构建时间开销不到 5%。我们也在不断应用优化以进一步减少其资源占用。 - **实用性强**:它不能阻止代码中_所有_可能出现的 nil panic,但它能捕获我们在生产环境中观察到的大多数潜在 nil panic,这使得 NilAway 能够在实用性和构建时间开销之间保持良好的平衡。 :star2: 欲了解更多详细的技术讨论,请查看我们的 [文档][docs]、[工程博客][blog] 和论文(编写中)。 ## 运行 NilAway NilAway 使用标准的 [go/analysis][go-analysis] 实现,使其易于与现有的分析器驱动(例如 [golangci-lint][golangci-lint]、[nogo][nogo] 或 [作为独立检查器运行][singlechecker])集成。 ### 独立检查器 通过运行以下命令从源码安装二进制文件: ``` go install go.uber.org/nilaway/cmd/nilaway@latest ``` 然后,通过以下命令运行 linter: ``` nilaway -include-pkgs="," ./... ``` ### golangci-lint (>= v1.57.0) NilAway 目前的形式可能会报告误报。这不幸地阻碍了它直接合并到 [golangci-lint][golangci-lint] 中并作为 linter 提供(参见 [PR#4045][pr-4045])。 因此,你需要将 NilAway 构建为 golangci-lint 的插件,以便作为私有 linter 执行。golangci-lint 中有两个插件系统,而使用 [Module Plugin System][golangci-lint-module-plugin](自 v1.57.0 引入)要容易得多,这也是在 golangci-lint 中运行 NilAway 唯一受支持的方法。 (1) 如果尚未在仓库根目录创建 `.custom-gcl.yml` 文件,请先创建它,并添加以下内容: ``` # This has to be >= v1.57.0 for module plugin system support. version: v1.57.0 plugins: - module: "go.uber.org/nilaway" import: "go.uber.org/nilaway/cmd/gclplugin" version: latest # Or a fixed version for reproducible builds. ``` (2) 将 NilAway 添加到 linter 配置文件 `.golangci.yaml` 中: 对于 golangci-lint v2: ``` version: "2" linters: enable: - nilaway settings: custom: nilaway: type: module description: Static analysis tool to detect potential nil panics in Go code. settings: # Settings must be a "map from string to string" to mimic command line flags: the keys are # flag names and the values are the values to the particular flags. include-pkgs: "" ```
对于 golangci-lint v1: ``` linters-settings: custom: nilaway: type: "module" description: Static analysis tool to detect potential nil panics in Go code. settings: # Settings must be a "map from string to string" to mimic command line flags: the keys are # flag names and the values are the values to the particular flags. include-pkgs: "" # NilAway can be referred to as `nilaway` just like any other golangci-lint analyzers in other # parts of the configuration file. ```
(3) 构建包含 NilAway 的自定义 golangci-lint 二进制文件: ``` # Note that your `golangci-lint` to bootstrap the custom binary must also be version >= v1.57.0. $ golangci-lint custom ``` 默认情况下,自定义二进制文件将构建在 `.` 目录下,名称为 `custom-gcl`,可以在 `.custom-gcl.yml` 文件中进一步自定义(说明请参见 [Module Plugin System][golangci-lint-module-plugin])。 (4) 运行自定义二进制文件而不是 `golangci-lint`: ``` # Arguments are the same as `golangci-lint`. $ ./custom-gcl run ./... ``` ### Bazel/nogo 使用 bazel/nogo 运行需要稍微多一些步骤。首先,请按照 [rules_go][rules-go]、[gazelle][gazelle] 和 [nogo][nogo] 的说明设置你的 Go 项目,使其能够通过 bazel/nogo 构建,并且不配置或仅配置默认的 linter 集合。然后, (1) 将 `import _ "go.uber.org/nilaway"` 添加到你的 `tools.go` 文件中(或你用于配置工具依赖项的其他文件,参见 Go Modules 文档中的[如何为模块跟踪工具依赖项?][track-tool-dependencies]),以避免 `go mod tidy` 将 NilAway 作为工具依赖项移除。 (2) 运行以下命令将 NilAway 作为工具依赖项添加到你的项目中: ``` # Get NilAway as a dependency, as well as getting its transitive dependencies in go.mod file. $ go get go.uber.org/nilaway@latest # This should not remove NilAway as a dependency in your go.mod file. $ go mod tidy # Run gazelle to sync dependencies from go.mod to WORKSPACE file. $ bazel run //:gazelle -- update-repos -from_file=go.mod ``` (3) 将 NilAway 添加到 nogo 配置中(通常在顶层的 `BUILD.bazel` 文件中): ``` nogo( name = "my_nogo", visibility = ["//visibility:public"], # must have public visibility deps = [ + "@org_uber_go_nilaway//:go_default_library", + "@org_uber_go_nilaway//config:go_default_library", # Add this line if your have rules_go < 0.55.0 ], config = "config.json", ) ``` (4) 运行 bazel build 以查看 NilAway 的工作情况(任何 nogo 错误都会停止 bazel 构建,你可以使用 `--keep_going` 标志来请求 bazel 尽可能多地进行构建): ``` $ bazel build --keep_going //... ``` (5) 关于如何向 nogo 驱动程序传递配置 JSON,请参阅 [nogo 文档][nogo-configure-analyzers];关于如何向 NilAway 传递配置,请参阅我们的[文档][nogo-configure-nilaway]。 ## 代码示例 让我们看几个示例,了解 NilAway 如何帮助防止 nil panic。 ``` // Example 1: var p *P if someCondition { p = &P{} } print(p.f) // nilness reports NO error here, but NilAway does. ``` 在此示例中,局部变量 `p` 仅在 `someCondition` 为真时初始化。在字段访问 `p.f` 处,如果 `someCondition` 为假,就可能发生 panic。NilAway 能够捕获这种潜在的 nil 流,并报告以下显示该 nilness 流的错误: ``` go.uber.org/example.go:12:9: error: Potential nil panic detected. Observed nil flow from source to dereference point: - go.uber.org/example.go:12:9: unassigned variable `p` accessed field `f` ``` 如果我们使用 nilness 检查(`if p != nil`)来保护此解引用,错误就会消失。 NilAway 还能捕获跨函数的 nil 流。例如,考虑以下代码片段: ``` // Example 2: func foo() *int { return nil } func bar() { print(*foo()) // nilness reports NO error here, but NilAway does. } ``` 在此示例中,函数 `foo` 返回一个 nil 指针,该指针在 `bar` 中被直接解引用,导致只要调用 `bar` 就会发生 panic。NilAway 能够捕获这种潜在的 nil 流,并报告以下错误,描述了跨函数边界的 nilness 流: ``` go.uber.org/example.go:23:13: error: Potential nil panic detected. Observed nil flow from source to dereference point: - go.uber.org/example.go:20:14: literal `nil` returned from `foo()` in position 0 - go.uber.org/example.go:23:13: result 0 of `foo()` dereferenced ``` 请注意,在上面的示例中,`foo` 不一定要与 `bar` 位于同一个包中。NilAway 也能够跟踪跨包的 nil 流。此外,NilAway 还能处理 Go 特定的语言结构,例如接收者、接口、类型断言、类型开关等。 ## 配置 我们通过 [go/analysis](https://pkg.go.dev/golang.org/x/tools/go/analysis) 中的标准标志传递机制公开了一组标志。 请查看 [docs/Configurations][docs-configurations] 以了解可用的标志,以及如何使用不同的 linter 驱动程序传递它们。 ## 支持 我们遵循与 [Go](https://golang.org/) 项目相同的[版本支持策略](https://go.dev/doc/devel/release#policy): 我们支持并测试 Go 的最后两个主要版本。 如果您有任何问题、错误报告或功能请求,请随时[提交 GitHub issue](https://github.com/uber-go/nilaway/issues)。 ## 许可证 该项目版权归 Uber Technologies, Inc. 2023 所有,并在 Apache 2.0 许可下授权。
标签:EVTX分析, Go, Ruby工具, SOC Prime, 云安全监控, 开发工具, 日志审计, 空指针检测, 静态分析