From 966c37c52b931c81ca8de3079a509d06a10d67b0 Mon Sep 17 00:00:00 2001 From: otegami Date: Fri, 6 Mar 2026 18:11:48 +0900 Subject: [PATCH] chore: add CI workflow for Ruby ASAN (AddressSanitizer) testing Add GitHub Actions workflow that runs a smoke test with ASAN-enabled Ruby to detect memory errors (buffer overflows, use-after-free, leaks) in the C extension layer. - Use ruby/setup-ruby with `ruby-version: asan` - LD_PRELOAD libstdc++ to work around __cxa_throw ASAN CHECK failures when non-ASAN DuckDB throws C++ exceptions internally - Test step uses continue-on-error until all ASAN issues are fixed - Cache DuckDB builds with ASAN-specific key to avoid collisions This workflow is a starting point. The plan is to incrementally fix ASAN-detected issues and eventually run the full test suite under ASAN. --- .github/workflows/ruby_asan_on_ubuntu.yml | 69 +++++++++++++++++++++++ test/duckdb_test/asan_test.rb | 10 ++++ 2 files changed, 79 insertions(+) create mode 100644 .github/workflows/ruby_asan_on_ubuntu.yml create mode 100644 test/duckdb_test/asan_test.rb diff --git a/.github/workflows/ruby_asan_on_ubuntu.yml b/.github/workflows/ruby_asan_on_ubuntu.yml new file mode 100644 index 00000000..ac59772c --- /dev/null +++ b/.github/workflows/ruby_asan_on_ubuntu.yml @@ -0,0 +1,69 @@ +name: Ruby ASAN + +on: + push: + branches: + - main + pull_request: + types: + - opened + - synchronize + - reopened + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + test: + runs-on: ubuntu-latest + timeout-minutes: 120 + strategy: + matrix: + duckdb: ['1.4.4', '1.3.2'] + + steps: + - uses: actions/checkout@v6 + + - name: Set up Ruby with ASAN + uses: ruby/setup-ruby@v1 + with: + ruby-version: asan + bundler-cache: true + + - name: duckdb cache + id: duckdb-cache + uses: actions/cache@v5 + with: + path: duckdb-v${{ matrix.duckdb }} + key: ${{ runner.os }}-asan-duckdb-v${{ matrix.duckdb }} + + - name: Build duckdb ${{ matrix.duckdb }} + env: + DUCKDB_VERSION: ${{ matrix.duckdb }} + if: steps.duckdb-cache.outputs.cache-hit != 'true' + run: | + git clone -b v$DUCKDB_VERSION https://github.com/duckdb/duckdb.git duckdb-tmp-v$DUCKDB_VERSION + cd duckdb-tmp-v$DUCKDB_VERSION && make && cd .. + rm -rf duckdb-v$DUCKDB_VERSION + mkdir -p duckdb-v$DUCKDB_VERSION/build/release/src duckdb-v$DUCKDB_VERSION/src + cp -rip duckdb-tmp-v$DUCKDB_VERSION/build/release/src/*.so duckdb-v$DUCKDB_VERSION/build/release/src + cp -rip duckdb-tmp-v$DUCKDB_VERSION/src/include duckdb-v$DUCKDB_VERSION/src/ + + - name: Build with ASAN Ruby + env: + DUCKDB_VERSION: ${{ matrix.duckdb }} + run: | + bundle exec rake build -- --with-duckdb-include=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/src/include --with-duckdb-lib=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/build/release/src/ + + - name: test with ASAN Ruby + # TODO: Remove continue-on-error once all ASAN issues are fixed. + continue-on-error: true + env: + DUCKDB_VERSION: ${{ matrix.duckdb }} + run: | + # LD_PRELOAD resolves __cxa_throw ASAN CHECK failure when DuckDB (built + # without ASAN) throws C++ exceptions internally. + # See: https://github.com/google/sanitizers/issues/934 + export LD_PRELOAD="$(realpath "$(gcc -print-file-name=libstdc++.so)")" + bundle exec ruby test/duckdb_test/asan_test.rb diff --git a/test/duckdb_test/asan_test.rb b/test/duckdb_test/asan_test.rb new file mode 100644 index 00000000..3121025e --- /dev/null +++ b/test/duckdb_test/asan_test.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require 'english' +require 'duckdb' + +begin + DuckDB::Database.open('not_exist_dir/not_exist_file') +rescue StandardError + puts "Error: #{$ERROR_INFO}" +end