В данном посте расскажем как анализировать проекты на языке Go, как это работает и как проанализировать проекты с системой сборки Bazel.
Мы поддержали в Svace сборку проектов для последней версии go 1.20. Также была поддержана базовая версия сборки проектов на Go для системы Bazel (только для дистрибутивов Linux). Данные изменения будут доступны в ближайшем релизе серии Svace 3.4.
При сборке проекта с помощью стандартной системы сборки go build схема использования будет выглядеть следующим образом:
svace init
svace build [команда сборки или скрипт сборки]
На данном этапе будет построено промежуточное представление для всего проекта и его зависимостей. Чтобы запустить анализ, необходимо использовать команду svace analyze.
Например, пройдем все шаги работы со Svace на проекте Xray-core. На момент написания статьи коммит 46d8bb5. В данном проекте используется версия go 1.20.
cd Xray-core
svace init
svace build go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
Получим следующий вывод:
Now Svace will preprocess captured data.
Processing source code markup data...
[**********************************************************************] 100%
Assembled build object: [BUILD]9078355afe76cf71d39d75ae3e47737a240fb4c4
Далее запустим анализ на данном проекте:
svace analyze
По окончании анализа будет выведен список и количество найденных предупреждений:
...
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
...
Далее все предупреждения можно будет увидеть в веб-интерфейсе Svacer.
При сборке с помощью встроенной системы go build, Svace будет перехватывать вызов исполняемого файла go. Далее исходя из аргументов go [build/install] с помощью go list будут найдены все зависимости для проекта.
В случае сборки с Bazel, внутренний процесс сборки проекта на Go происходит по-другому. Во-первых, Bazel не использует вызов go build напрямую, а самостоятельно компилирует и линкует проект с помощью go tool [compile/link и т.д.] команд. Во-вторых, информация о зависимостях передается с помощью правил (go-rules), а именно go_repository, которая с помощью go mod download скачивает исходные коды библиотек во внутреннюю GOPATH вашего проекта, которую Bazel создает сам. Детальное описание работы сборки Go в Bazel можно посмотреть здесь.
Мы поддержали базовую версию анализа проектов, использующих Bazel, которая также будет доступна в ближайшем релизе серии Svace 3.4.
Чтобы проанализировать проект, использующий Bazel, предварительно необходимо запустить следующие команды (иначе не все компиляции будут перехвачены):
bazel clean --expunge # для очистки кэша
bazel shutdown # для остановки сервера компиляций bazel
Далее svace build должен содержать следующий флаг: --enable-ptrace-all, без него соответствующие команды компиляции go tool [command] перехвачены не будут.
Если вы хотите проанализировать только Go компиляции, то дополнительно добавьте флаги --disable-language all, --enable-language go, благодаря которым будут перехватываться/анализироваться только Go компиляции. Можно использовать как с svace build, так и с svace analyze.
Например, команда сборки вашего проекта: bazel build //..., то svace build будет выглядеть так:
svace build --disable-language all --enable-language go --enable-ptrace-all bazel build //...
Также для корректной работы Svace папка проекта .svace-dir должна быть создана внутри корня анализируемого проекта (актуально только для проектов Bazel).
svace build будет также работать при использовании bazelisk.
Для примера рассмотрим проект bazel-ethereum. Версия Go в go.mod: go 1.15:
cd bazel-go-ethereum
bazel clean --expunge
bazel shutdown
svace init
svace build --enable-ptrace bazelisk build --spawn_strategy=local --define version="local" //...
Запускаем анализ:
svace analyze --disable-language all --enable-language go // т.к. также перехватились C/C++ компиляции
По окончании анализа будет выведен список и количество найденных предупреждений:
...
Goa import time: 6s
Warning suppression...
Suppression time: 684ms
Analysis results:
[BUFFER_OVERFLOW]
DYNAMIC_OVERFLOW: 5
OVERFLOW_UNDER_CHECK: 2
OVERFLOW_UNDER_CHECK.PROC: 1
...
Total warnings: 4415
...
Далее все предупреждения можно будет увидеть в веб-интерфейсе Svacer.
Наш компонент перехвата сборки отслеживает низкоуровневую команду go tool compile; в режиме модулей, также перехватываются команды go mod download. Внутри папки .svace-dir/bitcode создается GOPATH (.gopath). Данная GOPATH будет использована при построении промежуточного представления необходимого для анализа, куда будут скачаны нужные версии зависимостей, заданные для установки с помощью go mod download через правило go_repository в таком формате:
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",
)
В другом случае, будет проанализирована последняя версия зависимости, исходный код которой будет скачан в Svace .gopath.