This blog post explains how to analyze projects written on Go programming language, how it works and how to analyze projects which are using Bazel build system.
Svace
now supports analysis for latest go 1.20
version.Svace
now supports basic analysis of Go project which are using Bazel (only for Linux distributions).These changes will be available in the upcoming Svace 3.4 release.
When using standard Go build command go build
the use case looks like this:
svace init
svace build [build command or build script]
At this stage, an intermediate representation will have been built for the entire project and its dependencies. In order to run the analysis you need to type svace analyze
.
Let’s analyze the project Xray-core as an example. We have used commit 46d8bb5
. Go version in go.mod
is 1.20.
cd Xray-core
svace init
svace build go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
The output to this is:
Now Svace will preprocess captured data.
Processing source code markup data...
[**********************************************************************] 100%
Assembled build object: [BUILD]9078355afe76cf71d39d75ae3e47737a240fb4c4
Now run the analysis on the project:
svace analyze
As the result we get a list of all the warnings found and the amount of said warnings:
...
Analysis results:
[BUFFER_OVERFLOW]
DYNAMIC_OVERFLOW: 3
OVERFLOW_UNDER_CHECK: 10
[DEAD_CODE]
REDUNDANT_COMPARISON.ALWAYS_FALSE: 51
UNREACHABLE_CODE: 479
UNREACHABLE_CODE.RET: 29
[DEREF_OF_NULL]
DEREF_AFTER_NULL: 9
DEREF_AFTER_NULL.EX: 22
DEREF_OF_NULL.ASSIGN: 2
DEREF_OF_NULL.COND: 1
...
Total warnings: 4263
...
After this you are be able to see all the warnings using Svacer web-interface.
When using built-in go build
build system Svace intercepts the call to go
executable file and using go [build/install]
arguments identifies all the required dependencies.
When using Bazel the build process of Go project is completely different. Firstly, Bazel doesn’t invoke go build
directly, but compiles and links project using go tool [compile/link etc.]
. Secondly, all the information about dependencies is passed via rules (go-rules
) go_repository
to be precise, which uses go mod download
to install source code of required libraries into internal GOPATH
of your project, which Bazel creates on its own. If you want to study Bazel more thoroughly, you can do so here.
We have supported basic project analysis for Bazel, which will be available in an upcoming Svace 3.4
release.
To analyze project with Bazel you have to run the following commands (otherwise some Go compilations may not be intercepted):
bazel clean --expunge # clean up cache
bazel shutdown # stop Bazel server processes
After that svace build
must be ran with --enable-ptrace-all
flag, or go tool [command]
won’t be intercepted at all.
If you want only to analyze Go compilations, you have to add --disable-language all
and --enable-language go
flags, which will intercept and analyze only Go compilations. They can be used with svace build
as well as with svace analyze
.
For example, if the build command of your project is bazel build //...
, then svace build
will be:
svace build --disable-language all --enable-language go --enable-ptrace-all bazel build //...
In order to ensure Svace
operates correctly, .svace-dir
directory must be created in analyzed project’s root (this is only required for Bazel projects).
svace build
will also work with bazelisk.
As a demonstration let’s analyze bazel-ethereum. Go version in go.mod
is set to go 1.15
:
cd bazel-go-ethereum
bazel clean --expunge
bazel shutdown
Run svace build
:
svace init
svace build --enable-ptrace bazelisk build --spawn_strategy=local --define version="local" //...
Run analysis:
svace analyze --disable-language all --enable-language go // C/C++ compilations were also intercepted
After the analysis ends, you will get a list of all the warnings found:
...
Analysis results:
[BUFFER_OVERFLOW]
DYNAMIC_OVERFLOW: 3
OVERFLOW_UNDER_CHECK: 10
[DEAD_CODE]
REDUNDANT_COMPARISON.ALWAYS_FALSE: 51
UNREACHABLE_CODE: 479
UNREACHABLE_CODE.RET: 29
[DEREF_OF_NULL]
DEREF_AFTER_NULL: 9
DEREF_AFTER_NULL.EX: 22
DEREF_OF_NULL.ASSIGN: 2
DEREF_OF_NULL.COND: 1
...
Total warnings: 4263
...
After this you are be able to see all the warnings using Svacer web-interface.
Our build interception component monitors a low-level go tool compile
command; in the module mode go mod download
is also intercepted. Inside of .svace-dir/bitcode
directory GOPATH (.gopath)
is created. This GOPATH
will be used in constructing intermediate representation, which is required for the analysis. All the dependencies which are given in go mod download
via a go_repository
rule will be downloaded in said directory in this format:
https://github.com/bazelbuild/bazel-gazelle/blob/master/repository.md#go_repository
# Download using "go mod download"
go_repository(
name = "com_github_pkg_errors",
importpath = "github.com/pkg/errors",
sum = "h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=",
version = "v0.8.1",
)
In other cases, the last version of a dependency will be analyzed, the source code of which is in Svace .gopath
.