From 67ebf84f461fe1d27373ef73dc4fdc0552533bd1 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Mon, 14 Sep 2026 15:42:24 -0600 Subject: [PATCH] Uniformly disable assertions on release builds and enable them for tests --- .github/workflows/ci.yaml | 22 +++++++++++++++++++++- src/c/_cffi_backend.c | 9 +++++++++ src/c/test_c.py | 11 +++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index eab17d70..87f17ee8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -188,6 +188,9 @@ jobs: cd .. && \ rm -rf libffi-3.4.6 CIBW_ENVIRONMENT_PASS_LINUX: CFLAGS # ensure that the build container can see our overridden build config + CIBW_ENVIRONMENT: >- + CPPFLAGS="$CPPFLAGS ${{ env.skip_artifact_upload == 'true' && '-UNDEBUG' || '-DNDEBUG' }}" + CFFI_TEST_ASSERTIONS=${{ env.skip_artifact_upload == 'true' && '1' || '0' }} CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.manylinux_img || 'manylinux2014' }} CIBW_MANYLINUX_I686_IMAGE: ${{ matrix.manylinux_img || 'manylinux2014' }} CIBW_MANYLINUX_AARCH64_IMAGE: ${{ matrix.manylinux_img || 'manylinux2014' }} @@ -287,6 +290,9 @@ jobs: CIBW_ENABLE: cpython-prerelease CIBW_TEST_REQUIRES: pytest setuptools meson-python ninja CIBW_TEST_COMMAND: pip install pip --upgrade; cd {project}; PYTHONUNBUFFERED=1 pytest + CIBW_ENVIRONMENT: >- + CPPFLAGS="$CPPFLAGS ${{ env.skip_artifact_upload == 'true' && '-UNDEBUG' || '-DNDEBUG' }}" + CFFI_TEST_ASSERTIONS=${{ env.skip_artifact_upload == 'true' && '1' || '0' }} MACOSX_DEPLOYMENT_TARGET: ${{ matrix.deployment_target || '11.0' }} SDKROOT: ${{ matrix.sdkroot || 'macosx' }} run: | @@ -375,6 +381,9 @@ jobs: CIBW_ENABLE: cpython-prerelease CIBW_TEST_REQUIRES: pytest setuptools meson-python ninja CIBW_TEST_COMMAND: ${{ matrix.test_cmd || 'python -m pytest {package}/src/c' }} + CIBW_ENVIRONMENT: >- + _CL_="$_CL_ ${{ env.skip_artifact_upload == 'true' && '/UNDEBUG' || '/DNDEBUG' }}" + CFFI_TEST_ASSERTIONS=${{ env.skip_artifact_upload == 'true' && '1' || '0' }} # FIXME: /testing takes ~45min on Windows and has some failures... # CIBW_TEST_COMMAND='python -m pytest {package}/src/c {package}/testing' run: | @@ -479,9 +488,12 @@ jobs: CIBW_TEST_SOURCES: cffi # Running tests from `testing/` will not work since they try to compile C code on device CIBW_TEST_COMMAND: python -m pytest -sv cffi/src/c/ + # Xcode forwards TEST_RUNNER_ variables into the simulator test process. + CIBW_TEST_ENVIRONMENT: TEST_RUNNER_CFFI_TEST_ASSERTIONS=${{ env.skip_artifact_upload == 'true' && '1' || '0' }} # Environment variables for the build CIBW_ENVIRONMENT: > CFLAGS="-I${LIBFFI_IOS_DIR}/include" + CPPFLAGS="$CPPFLAGS ${{ env.skip_artifact_upload == 'true' && '-UNDEBUG' || '-DNDEBUG' }}" LDFLAGS="-L${LIBFFI_IOS_DIR}/lib" PYTHONUNBUFFERED=1 # Pass through our custom env vars @@ -535,6 +547,10 @@ jobs: pytest-run-parallel: needs: make_run_parallel_matrix + env: + CPPFLAGS: -UNDEBUG + _CL_: /UNDEBUG + CFFI_TEST_ASSERTIONS: '1' strategy: fail-fast: false matrix: ${{ fromJSON(needs.make_run_parallel_matrix.outputs.matrix_json) }} @@ -562,13 +578,17 @@ jobs: clang_TSAN: runs-on: ubuntu-24.04 container: ghcr.io/nascheme/numpy-tsan:3.15t-dev + env: + CFLAGS: -g -O0 -fsanitize=thread + CPPFLAGS: -UNDEBUG + CFFI_TEST_ASSERTIONS: '1' steps: - uses: actions/checkout@v7 - name: build and install run: | python -m pip install setuptools meson-python ninja pytest pytest-run-parallel - CFLAGS="-g -O3 -fsanitize=thread" python -m pip install -v . + python -m pip install -v . - name: run tests under pytest-run-parallel run: | diff --git a/src/c/_cffi_backend.c b/src/c/_cffi_backend.c index 6ef9b30e..a9bc9c5a 100644 --- a/src/c/_cffi_backend.c +++ b/src/c/_cffi_backend.c @@ -7585,6 +7585,14 @@ static _cffi_double_complex_t _testfunc25(double a, double b) } #endif +static int _testfunc26(void) +{ + /* Report whether assert expressions are evaluated in this build. */ + int enabled = 0; + assert(++enabled); + return enabled; +} + static PyObject *b__testfunc(PyObject *self, PyObject *args) { /* for testing only */ @@ -7621,6 +7629,7 @@ static PyObject *b__testfunc(PyObject *self, PyObject *args) case 24: f = &_testfunc24; break; case 25: f = &_testfunc25; break; #endif + case 26: f = &_testfunc26; break; default: PyErr_SetNone(PyExc_ValueError); return NULL; diff --git a/src/c/test_c.py b/src/c/test_c.py index f9d76665..8ddea1fb 100644 --- a/src/c/test_c.py +++ b/src/c/test_c.py @@ -1,6 +1,7 @@ from __future__ import annotations import contextlib +import os import traceback import unittest.mock @@ -1222,6 +1223,16 @@ def test_call_function_23_bool_array(): assert res == 1000 pytest.raises(ValueError, f, b"\x02\x02") +def test_backend_assertions(): + expected = os.environ.get('CFFI_TEST_ASSERTIONS') + if expected is None and not os.environ.get('GITHUB_ACTIONS'): + pytest.skip("CFFI_TEST_ASSERTIONS is not set") + assert expected in ('0', '1') + BInt = new_primitive_type("int") + BFunc = new_function_type((), BInt, False) + f = cast(BFunc, _testfunc(26)) + assert f() == int(expected) + def test_cannot_pass_struct_with_array_of_length_0(): BInt = new_primitive_type("int") BArray0 = new_array_type(new_pointer_type(BInt), 0)