Skip to content

Commit

Permalink
CI: Run sanitizers in docker (#580)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-e1off authored Jan 30, 2025
1 parent c9ee151 commit d9eddf1
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 46 deletions.
31 changes: 18 additions & 13 deletions .github/workflows/sanitize.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,31 @@ concurrency:
cancel-in-progress: true

jobs:
get_dependencies:
name: "Dependencies"
if: github.event.review.state == 'APPROVED'
uses: ./.github/workflows/dependencies.yaml

build_and_run_sanitizer:
name: ${{ matrix.mode }}
needs: get_dependencies
strategy:
matrix:
mode: ["asan", "msan", "tsan", "ubsan"]
fail-fast: false
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
if: github.event.review.state == 'APPROVED'
steps:
- uses: actions/checkout@v4
- uses: actions/cache/restore@v4
with:
path: deps
key: ${{ needs.get_dependencies.outputs.cache_key }}
- name : Purge runner
# Strip the runner to avoid space quota exceeding
run: |
sudo apt-get purge -y \
azure-cli microsoft-edge-stable google-cloud-cli \
google-chrome-stable temurin-21-jdk temurin-17-jdk \
temurin-11-jdk dotnet-sdk-8.0 firefox temurin-8-jdk \
powershell libllvm17t64 libllvm18 libllvm16t64 \
openjdk-21-jre-headless mysql-server-core-8.0
sudo apt-get autoremove
sudo apt-get autoclean
- name: Build [${{ matrix.mode }}]
run: ${{ github.workspace }}/.github/workflows/sanitizers/build_sanitizer.sh ${{ matrix.mode }}
run: |
docker build -f ${{ github.workspace }}/docker/sanitizers/Dockerfile \
--no-cache --build-arg SANITIZER_NAME=${{ matrix.mode }} \
-t sanitizer-${{ matrix.mode }} .
- name: UT [c++,${{ matrix.mode }}]
run: ${{ github.workspace }}/cmake.bld/Linux/run-unittests.sh
run: docker run --rm sanitizer-${{ matrix.mode }}
17 changes: 16 additions & 1 deletion docker/build_deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,22 @@

# This script downloads, builds, and installs the required build dependencies of BMQ
# from github.com/bloomberg. Software packages are installed to the /opt/bb prefix.
# If the optional argument '--only-download' is provided, the script will only download
# dependencies (build and install steps are skipped).

set -euxo pipefail

if [ $# == 1 ]; then
if [[ $1 == "--only-download" ]]; then
DO_BUILD=false
else
echo "Unexpected optional argument, only '--only-download' is supported"
exit 1
fi
else
DO_BUILD=true
fi

fetch_git() {
local org=$1
local repo=$2
Expand Down Expand Up @@ -68,4 +81,6 @@ build() {

fetch_deps
configure
build
if [ "${DO_BUILD}" = true ]; then
build
fi
23 changes: 23 additions & 0 deletions docker/sanitizers/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# syntax=docker/dockerfile:1

FROM docker.io/ubuntu:24.04

# Check if SANITIZER_NAME argument is passed
ARG SANITIZER_NAME
RUN if [ -z $SANITIZER_NAME ]; then \
echo "Required SANITIZER_NAME build argument is not passed." ;\
exit 1 ;\
fi

# Copy blazingmq source code
WORKDIR /blazingmq
COPY docker docker
COPY etc etc
COPY src src
COPY CMakeLists.txt ./

# Build with sanitizer instrumentation
RUN docker/sanitizers/build_sanitizer.sh ${SANITIZER_NAME}

# Run unit tests
CMD [ "/blazingmq/cmake.bld/Linux/run-unittests.sh" ]
25 changes: 25 additions & 0 deletions docker/sanitizers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Purpose
This folder contains scripts to run BlazingMQ and its dependencies under sanitizer (asan, msan, tsan and ubsan) in Docker container.

Usually sanitizers check is done on CI, but using Docker it is possible to run sanitizers check in both CI and local environment.

## Running sanitizer check in local environment to debug sanitizer issues
- Prerequisites: docker should be installed;
- Run docker build from the BlazingMQ root folder:
```
docker build -f docker/sanitizers/Dockerfile --no-cache --build-arg SANITIZER_NAME=<sanitizer-name> -t sanitizer-<sanitizer-name> .
```
NOTE: `sanitizer-name` is `asan`, `msan`, `tsan` or `ubsan`.

- Run docker container with unit tests
```
docker run --rm sanitizer-<sanitizer-name>
```
NOTE: `sanitizer-name` - sanitizer's name from previous step.

For debbugging, it is possible to run docker container with `/bin/bash` option and run desired tests manually, e.g.
```
docker run --rm -it sanitizer-<sanitizer-name> /bin/bash
root@923efd7529a4:/blazingmq# cd cmake.bld/Linux && ./run-env.sh ctest -R <test-name>
```
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# - Clang
# - LLVM libc++ standard library
# - A CMake toolchain file specific for instrumented build
# It is currently used to build instrumented BlazingMQ binaries for CI for all
# It is used to build instrumented BlazingMQ binaries for all
# Clang sanitizers (i.e. Address/Leak, Memory, Thread, UndefinedBehavior).
#
# It performs the following:
Expand All @@ -18,11 +18,10 @@
# 6) Build sanitizer-instrumented BlazingMQ unit tests.
# 7) Generate scripts to run unit tests:
# ./cmake.bld/Linux/run-unittests.sh
# This script is used as-is by CI to run unit tests under sanitizer.

set -eux

# :: Required arguments :::::::::::::::::::::::::::::::::::::::::::::::::::::::
# Check required arguments
if [ -z "${1}" ]; then
echo 'Error: Missing sanitizer name.' >&2
echo ' (Usage: build_sanitizer.sh <sanitizer-name>)' >&2
Expand All @@ -31,19 +30,11 @@ fi

SANITIZER_NAME="${1}"

# Github's 'ubuntu-22.04' image contains a lot of preinstalled tools,
# see https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2204-Readme.md.
# Uninstall uneeded tools which cause of versions clash.
sudo apt-get purge \
llvm-14 \
clang-14 \
gcc-9 \
gcc-10 \
gcc-11 \
gcc-12

# Install prerequisites
sudo apt-get update && sudo apt-get install -qy \
# Set up CA certificates first before installing other dependencies
apt-get update && \
apt-get install -y ca-certificates && \
apt-get install -qy --no-install-recommends \
lsb-release \
wget \
software-properties-common \
Expand All @@ -54,31 +45,33 @@ sudo apt-get update && sudo apt-get install -qy \
ninja-build \
bison \
libfl-dev \
pkg-config
pkg-config \
&& rm -rf /var/lib/apt/lists/*

# Install prerequisites for LLVM: latest cmake version, Ubuntu apt repository contains cmake version 3.22.1
# Install prerequisites for LLVM: latest cmake version, Ubuntu apt repository contains stale version
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null \
| gpg --dearmor - \
| sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null
sudo apt-add-repository -y "deb https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main"
sudo apt-get install -qy cmake
| tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null
apt-add-repository -y "deb https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main"
apt-get install -qy cmake

# Install LLVM
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
LLVM_VERSION=17
sudo ./llvm.sh ${LLVM_VERSION} all
LLVM_VERSION=18
LLVM_TAG="llvmorg-18.1.8"
./llvm.sh ${LLVM_VERSION} all

# Create version-agnostic pointers to required LLVM binaries.
sudo ln -sf /usr/bin/clang-${LLVM_VERSION} /usr/bin/clang
sudo ln -sf /usr/bin/clang++-${LLVM_VERSION} /usr/bin/clang++
sudo ln -sf /usr/bin/llvm-symbolizer-${LLVM_VERSION} /usr/bin/llvm-symbolizer
ln -sf /usr/bin/clang-${LLVM_VERSION} /usr/bin/clang
ln -sf /usr/bin/clang++-${LLVM_VERSION} /usr/bin/clang++
ln -sf /usr/bin/llvm-symbolizer-${LLVM_VERSION} /usr/bin/llvm-symbolizer

# Set some initial constants
PARALLELISM=8

DIR_ROOT="${PWD}"
DIR_SCRIPTS="${DIR_ROOT}/.github/workflows/sanitizers"
DIR_SCRIPTS="${DIR_ROOT}/docker/sanitizers"
DIR_EXTERNAL="${DIR_ROOT}/deps"
DIR_SRCS_EXT="${DIR_EXTERNAL}/srcs"
DIR_BUILD_EXT="${DIR_EXTERNAL}/cmake.bld"
Expand Down Expand Up @@ -111,24 +104,28 @@ github_url() { echo "https://github.com/$1.git"; }
# Download external dependencies
mkdir -p "${DIR_SRCS_EXT}"

# Download LLVM
LLVM_TAG="llvmorg-17.0.6"
# Download LLVM sources
curl -SL "https://github.com/llvm/llvm-project/archive/refs/tags/${LLVM_TAG}.tar.gz" \
| tar -xzC "${DIR_SRCS_EXT}"
mv "${DIR_SRCS_EXT}/llvm-project-${LLVM_TAG}" "${DIR_SRCS_EXT}/llvm-project"

# Download google-benchmark
GOOGLE_BENCHMARK_TAG="v1.8.4"
# Download google-benchmark sources
GOOGLE_BENCHMARK_TAG="v1.9.1"
checkoutGitRepo "$(github_url google/benchmark)" "${GOOGLE_BENCHMARK_TAG}" "google-benchmark"

# Download googletest
GOOGLETEST_TAG="v1.14.0"
# Download googletest sources
GOOGLETEST_TAG="v1.15.2"
checkoutGitRepo "$(github_url google/googletest)" "${GOOGLETEST_TAG}" "googletest"

# Download zlib
ZLIB_TAG="v1.3.1"
checkoutGitRepo "$(github_url madler/zlib)" "${ZLIB_TAG}" "zlib"

# Download bde-tools, bde and ntf-core sources
cd "${DIR_EXTERNAL}"
"${DIR_ROOT}"/docker/build_deps.sh "--only-download"
cd -

# Build libc++ with required instrumentation
#
# The extent to which all dependencies to be compiled with sanitizer-support
Expand Down Expand Up @@ -236,6 +233,11 @@ cmake -B "${DIR_SRCS_EXT}/zlib/cmake.bld" -S "${DIR_SRCS_EXT}/zlib" \
cmake --build "${DIR_SRCS_EXT}/zlib/cmake.bld" -j${PARALLELISM}
cmake --install "${DIR_SRCS_EXT}/zlib/cmake.bld"

# Remove un-needed folders
rm -rf "${DIR_BUILD_EXT}"
rm -rf "${DIR_SRCS_EXT}/bde"
rm -rf "${DIR_SRCS_EXT}/ntf-core"

# Build BlazingMQ
PKG_CONFIG_PATH="/opt/bb/lib64/pkgconfig:/opt/bb/lib/pkgconfig:/opt/bb/share/pkgconfig:$(pkg-config --variable pc_path pkg-config)" \
cmake -B "${DIR_BUILD_BMQ}" -S "${DIR_SRC_BMQ}" -G Ninja \
Expand Down
File renamed without changes.
File renamed without changes.

0 comments on commit d9eddf1

Please sign in to comment.