警告
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下獲得許可。