警告
Nilaway目前正在积极发展中:误报和破坏变化可能会发生。我们非常感谢任何反馈和贡献!
Nilaway是一种静态分析工具,旨在通过在编译时间而不是运行时捕获开发人员来避免生产中的无恐慌。 Nilaway与标准的NILNESS分析仪相似,但是,它采用了更复杂和功能强大的静态分析技术来跟踪包装中包装中的零流以及在包装中的零流,并报告错误为用户提供NIL NILNESS流量,以便更轻松地调试。
Nilaway享有使其脱颖而出的三个关键特性:
它是完全自动化的:Nilaway配备了推理引擎,因此除了标准GO代码之外,它不需要开发人员(例如,注释)提供任何其他信息。
它很快:我们设计了Nilaway的快速和可扩展性,使其适用于大型代码库。在我们的测量值中,我们观察到启用Nilaway时的构建时间开销不到5%。我们还在不断地应用优化以进一步减少其足迹。
它是实用的:它不能阻止您的代码中所有可能的零恐慌,但是它捕捉到了我们在生产中观察到的大多数潜在的零恐慌,从而使Nilaway能够在有用性和建筑时间开销之间保持良好的平衡。
?有关更详细的技术讨论,请查看我们的Wiki,工程博客和纸质(WIP)。
Nilaway是使用标准GO/分析实施的,使其易于与现有的分析仪驱动程序(即Golangci-Lint,Nogo或作为独立检查器运行)集成。
重要的
默认情况下,Nilaway分析所有GO代码,包括标准库和依赖项。这有助于Nilaway更好地理解代码形式的依赖性并减少其假否定性。但是,这也会产生大量的性能成本(对于具有模块化支持的驾驶员仅一次),并增加依赖关系中的不可动作错误的数量,对于具有很多依赖性的大型GO项目。
我们强烈建议使用Include-PKGS标志专门将分析范围缩小到您的项目代码。这指导Nilaway跳过分析依赖项(例如,第三方库),使您只能专注于Nilaway在第一方代码中报告的潜在零恐慌!
重要的
由于Nilaway进行的分析的复杂性,Nilaway通过GO/Analysis框架的事实机制缓存了有关特定软件包的发现。因此,强烈建议利用支持模块化分析的驱动程序(即,bazel/nogo或golangci-lint,而不是独立的检查器,因为它将所有事实存储在内存中),以在大型项目上更好地绩效。由于很容易开始,因此提供了更多用于评估目的的独立检查器。
通过运行来安装来自源的二进制文件:
go install go.uber.org/nilaway/cmd/nilaway@latest然后,通过:
nilaway -include-pkgs= " <YOUR_PKG_PREFIX>,<YOUR_PKG_PREFIX_2> " ./...提示
当输出为JSON时,禁用pretty-print标志:
nilaway -json -pretty-print=false -include-pkgs= " <YOUR_PKG_PREFIX>,<YOUR_PKG_PREFIX_2> " ./...Nilaway以目前的形式可以报告误报。不幸的是,这阻碍了其在Golangci-lint中的立即合并,并作为林格提供(请参阅PR#4045)。因此,您需要将Nilaway构建为Golangci-lint的插件,以作为私人衬里执行。 Golangci-lint中有两个插件系统,使用模块插件系统(自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 :
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 : " <YOUR_PACKAGE_PREFIXES> "
# 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文件中进一步自定义(有关说明,请参见模块插件系统)。
提示
缓存自定义二进制文件以避免必须再次构建它以节省资源,如果您使用固定版本的Nilaway,则可以将.custom-gcl.yml文件的哈希作为缓存密钥。如果您使用的是latest AS Nilaway版本,则可以将构建日期附加到缓存键,以在特定时间段内强制缓存到期。
(4)运行自定义二进制而不是golangci-lint :
# Arguments are the same as `golangci-lint`.
$ ./custom-gcl run ./...与Bazel/Nogo一起跑步需要更多的努力。首先按照Rule_go,Gazelle和Nogo的说明进行设置,以设置您的GO项目,以便可以使用未配置的linters的Bazel/Nogo构建Bazel/Nogo。然后,
(1)将import _ "go.uber.org/nilaway"添加到您的tools.go中。go文件(或您用于配置工具依赖项的其他文件,请参阅如何跟踪模块的工具依赖项?从GO模块文档中),以避免使用nilaway作为工具依赖性,从而避免go mod tidy 。
(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",
],
config = "config.json",
) (4)运行Bazel构建以查看Nilaway的工作(任何Nogo错误都会阻止Bazel构建,您可以使用--keep_going Flag要求Bazel尽可能多地构建Bazel):
$ bazel build --keep_going //...(5)请参阅有关如何将配置JSON传递给Nogo驱动程序的Nogo文档,并查看有关如何将配置传递给Nilaway的Wiki页面。
让我们看一些例子,看看Nilaway如何有助于防止零恐慌。
// Example 1:
var p * P
if someCondition {
p = & P {}
}
print ( p . f ) // nilness reports NO error here, but NilAway does.在此示例中,只有在someCondition为true时才初始化局部变量p在现场访问pf上,如果someCondition是错误的,可能会发生恐慌。 Nilaway能够捕获这种潜在的零流量,并报告以下错误,显示了这种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还能够在功能上捕获零流量。例如,考虑以下代码段:
// Example 2:
func foo () * int {
return nil
}
func bar () {
print ( * foo ()) // nilness reports NO error here, but NilAway does.
}在此示例中,该函数foo返回一个零指针,该指针直接在bar中删除,每当调用bar时会引起恐慌。 Nilaway能够捕获这种潜在的零流量并报告以下错误,描述了跨函数边界的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也能够跟踪零售包的零流。此外,Nilaway手柄特定于GO的语言结构,例如接收器,接口,类型断言,类型开关等。
我们在GO/分析中通过标准标志传递机制公开一组标志。请检查Wiki/配置以查看可用的标志以及如何使用不同的Linter驱动程序传递它们。
我们遵循与GO项目相同的版本支持策略:我们支持和测试GO的最后两个主要版本。
如果您有任何疑问,错误报告和功能请求,请随时打开GitHub问题。
我们希望您能为Nilaway做出贡献!请注意,一旦您创建了拉动请求,就会要求您签署我们的Uber贡献者许可协议。
该项目是版权2023 Uber Technologies,Inc。,并在Apache 2.0下获得许可。