diff --git a/docker/check-tool-versions.sh b/docker/check-tool-versions.sh new file mode 100755 index 0000000000..db20be45e4 --- /dev/null +++ b/docker/check-tool-versions.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Verify that every tool expected in the Nix CI env is present and runnable. +set -euo pipefail + +ccache --version +clang --version +clang++ --version +clang-format --version +cmake --version +conan --version +g++ --version +gcc --version +gcovr --version +git --version +less --version +make --version +mold --version +ninja --version +perl --version +pkg-config --version +pre-commit --version +python3 --version +run-clang-tidy --help +vim --version diff --git a/docker/install-sanitizer-libs.sh b/docker/install-sanitizer-libs.sh new file mode 100755 index 0000000000..a28efeab3f --- /dev/null +++ b/docker/install-sanitizer-libs.sh @@ -0,0 +1,89 @@ +#!/bin/bash +# Install sanitizer runtime libraries required to run binaries compiled with: +# -fsanitize=address → libasan.so.8 +# -fsanitize=thread → libtsan.so.2 +# -fsanitize=undefined → libubsan.so.1 +# +# The exact SONAMEs required depend on the compiler toolchain used to build the +# test binaries (see nix/ci-env.nix). If the toolchain is bumped and SONAMEs +# change, update the list below (or detect them from the binaries). +# +# Supported base images: +# debian:bookworm +# ubuntu:20.04 +# rhel:9 +# nixos/nix — tests are skipped; this script is not called + +set -euo pipefail + +if [ ! -f /etc/os-release ]; then + echo "ERROR: /etc/os-release not found; cannot detect OS" >&2 + exit 1 +fi + +# shellcheck source=/dev/null +. /etc/os-release + +echo "Detected OS: ${ID} ${VERSION_ID:-}" + +case "${ID}" in + debian) + apt-get update -y + apt-get install -y --no-install-recommends \ + libasan8 \ + libtsan2 \ + libubsan1 + + apt-get clean + rm -rf /var/lib/apt/lists/* + ;; + + ubuntu) + apt-get update -y + apt-get install -y --no-install-recommends \ + gnupg \ + software-properties-common + add-apt-repository -y ppa:ubuntu-toolchain-r/test + apt-get update -y + apt-get install -y --no-install-recommends \ + libasan8 \ + libtsan2 \ + libubsan1 + + apt-get clean + rm -rf /var/lib/apt/lists/* + ;; + + rhel | centos | rocky | almalinux) + dnf install -y \ + libasan8 \ + libtsan2 \ + libubsan + + dnf clean -y all + rm -rf /var/cache/dnf/* + ;; + + *) + echo "ERROR: unsupported OS '${ID}'. Supported: debian, ubuntu, rhel-family" >&2 + exit 1 + ;; +esac + +# Verify that every expected library is now resolvable by the dynamic linker. +missing=0 +for lib in libasan.so.8 libtsan.so.2 libubsan.so.1; do + if ldconfig -p | grep -q "${lib}"; then + echo "OK: ${lib} found" + else + echo "ERROR: ${lib} not found after installation" >&2 + missing=$((missing + 1)) + fi +done + +if [ "${missing}" -ne 0 ]; then + echo "ERROR: ${missing} library/libraries missing" >&2 + exit 1 +fi + +echo "All sanitizer runtime libraries installed successfully." diff --git a/docker/nix.Dockerfile b/docker/nix.Dockerfile index 3c5dbcb734..a0eab31769 100644 --- a/docker/nix.Dockerfile +++ b/docker/nix.Dockerfile @@ -32,7 +32,7 @@ FROM ${BASE_IMAGE} AS final ARG BASE_IMAGE # bash is not located at /bin/bash in nixos/nix, so we need to create a symlink to it. -RUN if [ -d /nix ]; then \ +RUN if echo "${BASE_IMAGE}" | grep -qiE 'nixos'; then \ ln -s /root/.nix-profile/bin/bash /bin/bash; \ fi @@ -65,38 +65,44 @@ if [ ! -e "${target}" ]; then fi EOF -RUN < function run() { @@ -18,27 +20,34 @@ function run() { out_file="$(mktemp)" echo "=== Run ${binary} ===" - local rc=0 - "${binary}" >"${out_file}" 2>&1 || rc=$? + set +e + "${binary}" >"${out_file}" 2>&1 + local rc=$? + set -e cat "${out_file}" + local failed=0 if [ "${expected_rc}" = "nonzero" ]; then if [ "${rc}" -eq 0 ]; then echo "ERROR: expected non-zero exit code from ${binary}, got ${rc}" >&2 - exit 1 + failed=1 fi elif [ "${rc}" -ne "${expected_rc}" ]; then echo "ERROR: expected exit code ${expected_rc} from ${binary}, got ${rc}" >&2 - exit 1 + failed=1 fi - grep -q "${expected_output}" "${out_file}" || - { - echo "ERROR: expected '${expected_output}' from ${binary}" >&2 - exit 1 - } - echo "OK: '${expected_output}' detected" + if ! grep -q "${expected_output}" "${out_file}"; then + echo "ERROR: expected '${expected_output}' from ${binary}" >&2 + failed=1 + fi + + if [ "${failed}" -eq 0 ]; then + echo "OK: '${expected_output}' detected" + else + failed_binaries+=("${binary}") + fi } declare -A expect=( @@ -52,6 +61,15 @@ declare -A expect=( for compiler in g++ clang++; do for name in regular asan tsan ubsan; do binary="${bins_dir}/${name}-${compiler}" + + if [ "${name}" = "tsan" ] && [ "${compiler}" = "g++" ] && + grep -qi 'debian' /etc/os-release 2>/dev/null && + [ "$(uname -m)" = "aarch64" ]; then + echo "=== Skipping ${binary} (tsan-g++ unsupported on Debian ARM64) ===" + echo " NOTE: to enable it, add --security-opt seccomp=unconfined to your docker run command" + continue + fi + if [ "${name}" = "regular" ]; then expected_rc=0 else @@ -60,3 +78,9 @@ for compiler in g++ clang++; do run "${binary}" "${expect[$name]}" "${expected_rc}" done done + +if [ "${#failed_binaries[@]}" -gt 0 ]; then + echo "ERROR: the following binaries failed:" >&2 + printf ' %s\n' "${failed_binaries[@]}" >&2 + exit 1 +fi diff --git a/nix/packages.nix b/nix/packages.nix index d209620a68..3d92fedb4b 100644 --- a/nix/packages.nix +++ b/nix/packages.nix @@ -15,6 +15,7 @@ in git gnumake llvmPackages_22.clang-tools + less # needed for git diff mold ninja patchelf