name: snmalloc CI # The following should ensure that the workflow only runs a single set of actions # for each PR. But it will not apply this to pushes to the main branch. concurrency: group: ${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} # Controls when the workflow will run on: # Triggers the workflow on push or pull request events but only for the master branch push: branches: [ main ] pull_request: branches: [ main, snmalloc1 ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: jobs: ubuntu: strategy: matrix: # Build each combination of OS and release/debug variants os: [ "ubuntu-24.04", "ubuntu-22.04", "ubuntu-24.04-arm" ] build-type: [ "Release", "Debug" ] # Extra cmake flags. GitHub Actions matrix overloads `include` to mean # 'add extra things to a job' and 'add jobs'. You can add extra things # to a job by specifying things that exist in a job created from the # matrix definition and adding things. You can specify extra jobs by # specifying properties that don't match existing jobs. We use # `cmake-flags` to add cmake flags to all jobs matching a pattern and # `extra-cmake-flags` to specify a new job with custom CMake flags. # # Note that adding new jobs does not *refine* existing matrix entries, # but rather adds new tuples wholesale. That is, specifying "os" alone # will result in a tuple without set "build-type" rather than one for # each existing "build-type" value! extra-cmake-flags: [ "" ] # Modify the complete matrix include: - os: "ubuntu-22.04" variant: "C++17" build-type: "Debug" extra-cmake-flags: "-DSNMALLOC_USE_CXX17=ON" # Add the self-host build, using the bounds-checked memcpy in # maximally paranoid mode (checking loads and stores) - os: "ubuntu-24.04" build-type: Debug self-host: true extra-cmake-flags: "-DSNMALLOC_MEMCPY_BOUNDS=ON -DSNMALLOC_CHECK_LOADS=ON" # Extra build to check using pthread library for destructing local state. - os: "ubuntu-24.04" variant: "with pthread destructors" build-type: Debug self-host: true extra-cmake-flags: "-DSNMALLOC_USE_PTHREAD_DESTRUCTORS=On" # Extra build to check using individual mitigations works. - os: "ubuntu-24.04" variant: "individual mitigations" build-type: Release self-host: true extra-cmake-flags: "-DSNMALLOC_BENCHMARK_INDIVIDUAL_MITIGATIONS=On -DSNMALLOC_BUILD_TESTING=Off" # Check that we can build specifically with libstdc++ - os: "ubuntu-24.04" variant: "libstdc++ (Build only)" build-type: Release extra-cmake-flags: "-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_FLAGS=-stdlib=libstdc++" build-only: yes # Replay some of the above tests with clang-10 specifically - os: "ubuntu-22.04" variant: "Traced Build" build-type: Release extra-cmake-flags: "-DSNMALLOC_TRACING=On" build-only: yes - os: "ubuntu-22.04" variant: "clang + libstdc++ (Build only)" build-type: Release extra-cmake-flags: "-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_FLAGS=-stdlib=libstdc++" build-only: yes # Don't abort runners if a single one fails fail-fast: false runs-on: ${{ matrix.os }} name: Ubuntu - ${{ matrix.os }} ${{ matrix.build-type }} ${{ matrix.variant }} steps: - uses: actions/checkout@v4 - name: Install build dependencies run: "sudo apt install ninja-build" - name: Configure CMake run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -G Ninja ${{ matrix.cmake-flags }} ${{ matrix.extra-cmake-flags }} # Build with a nice ninja status line - name: Build working-directory: ${{github.workspace}}/build run: NINJA_STATUS="%p [%f:%s/%t] %o/s, %es" ninja - name: Test file size of binaries is sane working-directory: ${{github.workspace}}/build run: "ls -l libsnmallocshim.* ; [ $(ls -l libsnmallocshim.* | awk '{ print $5}') -lt 10000000 ]" # If the tests are enabled for this job, run them - name: Test if: ${{ matrix.build-only != 'yes' }} working-directory: ${{github.workspace}}/build run: ctest --output-on-failure -j 4 -C ${{ matrix.build-type }} --timeout 400 - name: Selfhost if: ${{ matrix.self-host }} working-directory: ${{github.workspace}}/build run: | mkdir libs cp libsnmallocshim*.so libs for lib in `ls libs`; do echo; echo Testing $lib; ninja clean; LD_PRELOAD=libs/$lib ninja libsnmallocshim.so; done bazel: strategy: matrix: # Build each combination of OS and release/debug variants os: [ "ubuntu-24.04", "ubuntu-22.04", "macos-13", "macos-14", "macos-15" ] build-type: [ "Release", "Debug" ] # Don't abort runners if a single one fails fail-fast: false runs-on: ${{ matrix.os }} name: Bazel - ${{ matrix.os }} ${{ matrix.build-type }} steps: - uses: actions/checkout@v4 - uses: bazelbuild/setup-bazelisk@v3 - name: Mount bazel cache # Optional uses: actions/cache@v4 with: path: "~/.cache/bazel" key: bazel-${{ matrix.os }}-${{ matrix.build-type }} - run: bazel build -c opt //:snmalloc - run: bazel build -c opt //:snmalloc-rs - run: bazel test -c opt --config=asan //fuzzing:snmalloc_fuzzer if: ${{ matrix.os != 'macos-13' && matrix.os != 'macos-14' && matrix.os != 'macos-15' }} # If this looks remarkably familiar, that's because it is. Sigh. macos: strategy: matrix: os: [ "macos-13", "macos-14", "macos-15" ] build-type: [ "Release", "Debug" ] extra-cmake-flags: [ "", "-DSNMALLOC_USE_CXX17=ON" ] fail-fast: false runs-on: ${{ matrix.os }} name: Mac OS ${{ matrix.os }} ${{ matrix.build-type }} ${{ matrix.extra-cmake-flags }} steps: - uses: actions/checkout@v4 - name: Install build dependencies # The homebrew packages are broken at the moment and error out # after trying to install Python as a dependency of ninja because # 2to3 exists. As a quick hack, delete it first. This should be # removed once the homebrew install is fixed. run: "rm -f /usr/local/bin/2to3 ; brew update && brew install ninja" - name: Pick the latest XCode in runner uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: latest-stable - name: Configure CMake run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -G Ninja ${{ matrix.cmake-flags }} ${{ matrix.extra-cmake-flags }} # Build with a nice ninja status line - name: Build working-directory: ${{github.workspace}}/build run: NINJA_STATUS="%p [%f:%s/%t] %o/s, %es" ninja - name: Test file size of binaries is sane working-directory: ${{github.workspace}}/build run: "ls -l libsnmallocshim.* ; [ $(ls -l libsnmallocshim.* | awk '{ print $5}') -lt 10000000 ]" # If the tests are enabled for this job, run them - name: Test if: ${{ matrix.build-only != 'yes' }} working-directory: ${{github.workspace}}/build run: ctest --output-on-failure -j 4 -C ${{ matrix.build-type }} --timeout 400 - name: Selfhost if: ${{ matrix.self-host }} working-directory: ${{github.workspace}}/build run: | mkdir libs cp libsnmallocshim*.so libs for lib in `ls libs`; do echo; echo Testing $lib; ninja clean; LD_PRELOAD=libs/$lib ninja libsnmallocshim.so; done # GitHub doesn't natively support *BSD, but we can run them in VMs on Mac / # Linux runners freebsd: strategy: matrix: # Build each combination of OS, version, and release/debug variants # FreeBSD and OpenBSD run on xhyve, netbsd needs qemu os: - version: '13.2' dependencies: pkg ins -y cmake ninja build-type: [ Release, Debug ] # Don't abort runners if a single one fails fail-fast: false # Kill these jobs if they take too long. timeout-minutes: 25 runs-on: ubuntu-22.04 name: FreeBSD-${{ matrix.os.version}} ${{ matrix.build-type }} steps: - uses: actions/checkout@v4 - uses: vmactions/freebsd-vm@v1 with: release: ${{ matrix.os.version}} usesh: true mem: 8192 copyback: false prepare: | ${{ matrix.os.dependencies }} run: | set -e cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -G Ninja cd ${{github.workspace}}/build NINJA_STATUS="%p [%f:%s/%t] %o/s, %es" ninja ctest -j 4 --output-on-failure -E '(perf-.*)|(.*-malloc$)' --timeout 400 netbsd: strategy: matrix: os: - version: '9.2' dependencies: | /usr/sbin/pkg_add cmake ninja-build gcc10 build-type: [ Release ] # Don't abort runners if a single one fails fail-fast: false # Kill these jobs if they take too long. timeout-minutes: 25 runs-on: ubuntu-22.04 name: NetBSD-${{ matrix.os.version}} ${{ matrix.build-type }} steps: - uses: actions/checkout@v4 - uses: vmactions/netbsd-vm@v1 with: release: ${{ matrix.os.version}} usesh: true mem: 8192 copyback: false prepare: | ${{ matrix.os.dependencies }} run: | set -e cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -G Ninja -DCMAKE_CXX_COMPILER=/usr/pkg/gcc10/bin/g++ -DCMAKE_C_COMPILER=/usr/pkg/gcc10/bin/gcc cd ${{github.workspace}}/build NINJA_STATUS="%p [%f:%s/%t] %o/s, %es" ninja ctest -j 4 --output-on-failure -E '(perf-.*)|(.*-malloc$)' --timeout 400 ## Without overcommit, or explicit commit the current implementation cannot be made to work on openbsd. ## We could add a layered pagemap for openbsd, that would address the requirements. # openbsd: # strategy: # matrix: # # Build each combination of OS, version, and release/debug variants # os: # - version: '7.2' # dependencies: pkg_add -I cmake ninja # build-type: [ Release, Debug ] # # Don't abort runners if a single one fails # fail-fast: false # # Kill these jobs if they take too long. # timeout-minutes: 25 # runs-on: macos-latest # name: OpenBSD-${{ matrix.os.version}} ${{ matrix.build-type }} # steps: # - uses: actions/checkout@v4 # - uses: vmactions/openbsd-vm@v0 # with: # release: ${{ matrix.os.version}} # usesh: true # mem: 8192 # copyback: false # prepare: | # ${{ matrix.os.dependencies }} # run: | # set -e # cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -G Ninja # cd ${{github.workspace}}/build # NINJA_STATUS="%p [%f:%s/%t] %o/s, %es" ninja # ctest -j 4 --output-on-failure -E '(perf-.*)|(.*-malloc$)' --timeout 400 sanitizer: strategy: matrix: # Build just release variant as Debug is too slow. build-type: [ Release ] os: ["ubuntu-24.04", "ubuntu-22.04"] include: - os: "ubuntu-22.04" variant: "libc++ (TSan + UBSan)" dependencies: "sudo apt install ninja-build libc++-dev" extra-cmake-flags: "-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_FLAGS=-stdlib=\"libc++ -g\" -DSNMALLOC_SANITIZER=undefined,thread" - os: "ubuntu-24.04" variant: "libc++ (TSan + UBSan)" dependencies: "sudo apt install ninja-build libc++-dev" extra-cmake-flags: "-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_FLAGS=-stdlib=\"libc++ -g\" -DSNMALLOC_SANITIZER=undefined,thread" # Don't abort runners if a single one fails fail-fast: false runs-on: ${{ matrix.os }} name: Sanitizer - ${{ matrix.os }} ${{ matrix.build-type }} ${{ matrix.variant }} steps: - uses: actions/checkout@v4 - name: Install build dependencies run: ${{ matrix.dependencies }} - name: Configure CMake run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -G Ninja ${{ matrix.cmake-flags }} ${{ matrix.extra-cmake-flags }} # Build with a nice ninja status line - name: Build working-directory: ${{github.workspace}}/build run: NINJA_STATUS="%p [%f:%s/%t] %o/s, %es" ninja - name: Test working-directory: ${{github.workspace}}/build run: ctest --output-on-failure -j 4 -C ${{ matrix.build-type }} --timeout 400 -E "memcpy|external_pointer" --repeat-until-fail 2 qemu-crossbuild: strategy: matrix: build-type: [ Release, Debug ] arch: - name: armhf system-processor: arm triple: arm-linux-gnueabihf rtld: ld-linux-armhf.so.3 ld-flavour: lld host-os: ubuntu-24.04 - name: arm64 system-processor: aarch64 triple: aarch64-linux-gnu rtld: ld-linux-aarch64.so.1 ld-flavour: lld host-os: ubuntu-24.04 # DISABLED as 20.04 is not supported anymore, # and it appears the qemu bug persists in 24.04 # See https://github.com/microsoft/snmalloc/issues/576 # - name: ppc64el # system-processor: powerpc64le # triple: powerpc64le-linux-gnu # rtld: ld64.so.2 # ld-flavour: lld # # See https://github.com/microsoft/snmalloc/issues/576 # host-os: ubuntu-24.04 - name: riscv64 system-processor: riscv64 triple: riscv64-linux-gnu rtld: ld-linux-riscv64-lp64d.so.1 extra-packages: binutils-riscv64-linux-gnu ld-flavour: bfd ld: /usr/bin/riscv64-linux-gnu-ld.bfd host-os: ubuntu-24.04 # Don't abort runners if a single one fails fail-fast: false runs-on: ${{matrix.arch.host-os}} name: Crossbuild - ${{matrix.build-type}} cross-build for ${{ matrix.arch.triple }} steps: - uses: actions/checkout@v4 - name: "Install cross-compile toolchain and QEMU (ubuntu-24.04)" if: matrix.arch.host-os == 'ubuntu-24.04' run: | sudo apt update sudo apt install libstdc++-12-dev-${{ matrix.arch.name }}-cross qemu-user ninja-build binfmt-support sudo apt install ${{matrix.arch.extra-packages}} - name: Reconfigure for PowerPC64LE if: startsWith(matrix.arch.triple, 'powerpc64le') # The default PowerPC qemu configuration uses the wrong page size. # Wrap it in a script that fixes this. run: | sudo update-binfmts --disable qemu-ppc64le sudo sh -c 'echo ":qemu-ppc64le:M:0:\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00:\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00:`pwd`/ppc64.sh:" > /proc/sys/fs/binfmt_misc/register' echo '#!/bin/sh' > ppc64.sh echo '/usr/bin/qemu-ppc64le -p 65536 $@' >> ppc64.sh chmod +x ppc64.sh - name: Configure env: SNMALLOC_CI_CLANG_VERSION: ${{ (matrix.arch.host-os == 'ubuntu-24.04') && 16 || 13 }} RTLD_NAME: ${{ matrix.arch.rtld }} ARCH: ${{ matrix.arch.system-processor }} TRIPLE: ${{ matrix.arch.triple}} run: > cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -G Ninja -DSNMALLOC_CI_BUILD=ON -DSNMALLOC_QEMU_WORKAROUND=ON -DSNMALLOC_STATIC_LIBRARY=OFF -DCMAKE_TOOLCHAIN_FILE=ci/Toolchain.cmake -DSNMALLOC_LINKER=${{matrix.arch.ld}} -DSNMALLOC_LINKER_FLAVOUR=${{matrix.arch.ld-flavour}} - name: Build working-directory: ${{github.workspace}}/build run: NINJA_STATUS="%p [%f:%s/%t] %o/s, %es" ninja # For debugging: verify that we've actually cross-compiled. - name: Run `file` for inspection working-directory: ${{github.workspace}}/build run: file func* # Run the tests, skipping the -malloc and perf- tests (perf doesn't make # sense in an emulator and the pass-through malloc is slightly flaky in # QEMU) - name: Test working-directory: ${{github.workspace}}/build run: ctest -j 2 --output-on-failure -E '(perf-.*)|(.*-malloc$)' --timeout 400 timeout-minutes: 30 windows: strategy: matrix: # Build each combination of OS and release/debug variants os: [ windows-2022, windows-2025 ] build-type: [ Release, Debug ] arch: [ Win32, x64 ] toolchain: [ "", "-T ClangCL" ] extra-cmake-flags: [ "" ] # Add an extra check for the Windows 8 compatible PAL include: - os: windows-2022 build-type: Release arch: x64 toolchain: "" extra-cmake-flags: -DWIN8COMPAT=TRUE variant: Windows 8 compatible - os: windows-2022 build-type: Release arch: Win32 toolchain: "" - os: windows-2022 build-type: Debug arch: Win32 toolchain: "" - os: windows-2022 build-type: Release arch: x64 toolchain: "" - os: windows-2022 build-type: Debug arch: x64 toolchain: "" - os: windows-2022 build-type: Release arch: ARM64 toolchain: "" build-only: yes - os: windows-2022 build-type: Debug arch: ARM64 toolchain: "" build-only: yes - os: windows-2022 build-type: Release arch: ARM64EC toolchain: "" extra-cmake-flags: -DCMAKE_SYSTEM_VERSION="10.0.22621.0" build-only: yes - os: windows-2022 build-type: Debug arch: ARM64EC toolchain: "" extra-cmake-flags: -DCMAKE_SYSTEM_VERSION="10.0.22621.0" build-only: yes # Don't abort runners if a single one fails fail-fast: false runs-on: ${{ matrix.os }} name: Windows - ${{ matrix.os }} ${{ matrix.arch }} ${{ matrix.build-type }} ${{ matrix.toolchain }} ${{ matrix.variant }} steps: - uses: actions/checkout@v4 - name: Configure CMake run: | cmake -B ${{github.workspace}}/build -A ${{ matrix.arch }} ${{ matrix.toolchain }} ${{ matrix.extra-cmake-flags }} -DSNMALLOC_CI_BUILD=On -DSNMALLOC_RUST_SUPPORT=On # Build with whatever version of msbuild was configured, for a single build configuration. - name: Build run: cmake --build ${{github.workspace}}/build -- /m /p:Configuration=${{ matrix.build-type }} # Run the tests. - name: Test if: ${{ matrix.build-only != 'yes' }} working-directory: ${{ github.workspace }}/build run: ctest -j 2 --interactive-debug-mode 0 --output-on-failure -C ${{ matrix.build-type }} --timeout 400 timeout-minutes: 20 # Job to run clang-format and report errors format: runs-on: ubuntu-22.04 name: Format check # We don't need to do the build for this job, but we need to configure it to get the clang-format target steps: - uses: actions/checkout@v4 - name: Install clang-tidy and clang-format run: | sudo apt update sudo apt install clang-tidy-15 clang-format-15 - name: Configure CMake run: cmake -B ${{github.workspace}}/build -DSNMALLOC_USE_CXX17=ON # Run the clang-format check and error if it generates a diff - name: Run clang-format working-directory: ${{github.workspace}}/build run: | set -eo pipefail make clangformat git diff --exit-code - name: Run clang-tidy run: | clang-tidy-15 src/snmalloc/override/malloc.cc -header-filter="`pwd`/*" -warnings-as-errors='*' -export-fixes=tidy.fail -- -std=c++17 -mcx16 -DSNMALLOC_USE_WAIT_ON_ADDRESS=1 -DSNMALLOC_PLATFORM_HAS_GETENTROPY=0 -Isrc if [ -f tidy.fail ] ; then cat tidy.fail exit 1 fi fuzzing: name: Fuzzing runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Configure CMake run: cmake -B ${{github.workspace}}/build -DSNMALLOC_ENABLE_FUZZING=ON -DFUZZTEST_FUZZING_MODE=ON -DCMAKE_CXX_COMPILER=clang++ - name: Build run: cmake --build ${{github.workspace}}/build --target snmalloc-fuzzer - name: Test run: ${{github.workspace}}/build/fuzzing/snmalloc-fuzzer self-vendored: strategy: fail-fast: false matrix: include: - os: windows-2022 cxx: clang-cl cc: clang-cl - os: ubuntu-24.04 cxx: clang++-18 cc: clang-18 - os: ubuntu-24.04 cxx: g++-14 cc: gcc-14 - os: macos-latest cxx: clang++ cc: clang runs-on: ${{ matrix.os }} name: Self Vendored STL - ${{ matrix.os }} ${{ matrix.cxx }} steps: - uses: actions/checkout@v4 - name: Prepare Windows if: runner.os == 'Windows' run: | choco upgrade llvm choco install ninja - name: Prepare macOS if: runner.os == 'macOS' run: | brew install ninja - name: Prepare Ubuntu if: runner.os == 'Linux' run: | sudo apt-get install -y ninja-build - name: Configure CMake run: > cmake -B ${{github.workspace}}/build -DSNMALLOC_USE_SELF_VENDORED_STL=ON -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} -DCMAKE_C_COMPILER=${{ matrix.cc }} - name: Build run: cmake --build ${{github.workspace}}/build --parallel - name: Test run: | cd ${{github.workspace}}/build ctest --parallel gwp-asan: strategy: fail-fast: false matrix: os: [ubuntu-24.04, ubuntu-24.04-arm] profile: [RelWithDebInfo, Debug] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - name: Install Ninja run: | sudo apt-get install -y ninja-build - name: Install Compiler-RT shell: bash run: | cd .. git clone https://github.com/llvm/llvm-project --depth=1 -b llvmorg-19.1.7 mkdir compiler-rt cmake -G Ninja \ -S llvm-project/runtimes \ -B llvm-project/build \ -DCMAKE_BUILD_TYPE=${{ matrix.profile }}\ -DLLVM_ENABLE_RUNTIMES=compiler-rt \ -DCMAKE_CXX_COMPILER=clang++-18 \ -DCMAKE_C_COMPILER=clang-18 \ -DCMAKE_INSTALL_PREFIX=$(realpath compiler-rt) cmake --build llvm-project/build --parallel cmake --build llvm-project/build --target=install - name: Configure SnMalloc run: > cmake -GNinja -B${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{ matrix.profile }} -DCMAKE_CXX_COMPILER=clang++-18 -DCMAKE_C_COMPILER=clang-18 -DSNMALLOC_ENABLE_GWP_ASAN_INTEGRATION=On -DSNMALLOC_GWP_ASAN_INCLUDE_PATH=${{github.workspace}}/../llvm-project/compiler-rt/lib -DSNMALLOC_GWP_ASAN_LIBRARY_PATH=${{github.workspace}}/../compiler-rt/lib/linux - name: Build run: cmake --build ${{github.workspace}}/build --parallel - name: Test run: | cd ${{github.workspace}}/build ctest --parallel --output-on-failure all-checks: # Currently FreeBSD and NetBSD CI are not working, so we do not require them to pass. # Add fuzzing back when the memove issue is fixed. needs: [ubuntu, macos, freebsd, netbsd, sanitizer, qemu-crossbuild, windows, format] runs-on: ubuntu-24.04 steps: - name: Dummy step run: true