# Gitea Actions workflow (not GitHub Actions — this project is hosted on # Gitea, see CONTRIBUTING.md). Gitea Actions' YAML is GitHub-Actions- # compatible, but two things here are Gitea-specific and need to match # your actual instance, not just this repo: # - `runs-on: ubuntu-latest` must match a label your registered Gitea # runner (act_runner) actually advertises; there is no GitHub-hosted- # runner equivalent, this is entirely self-hosted. # - `uses: actions/checkout@v4` resolves against whatever action source # your instance's runner is configured with (by default, Gitea Actions # fetches actions from github.com unless DEFAULT_ACTIONS_URL is # overridden); use `https://gitea.com/actions/checkout@v4` instead if # your runner is configured to disallow GitHub as an action source. name: CI on: push: pull_request: jobs: build-and-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build static + shared library run: make all - name: Run test suite run: make test - name: Build and run under AddressSanitizer + UndefinedBehaviorSanitizer run: | mkdir -p build/san for f in src/*.c; do cc -std=c11 -Wall -Wextra -O1 -g -fPIC -Iinclude -Isrc -D_GNU_SOURCE \ -fsanitize=address,undefined -c "$f" -o "build/san/$(basename "${f%.c}").o" done for t in tests/test_*.c; do name=$(basename "${t%.c}") cc -std=c11 -O1 -g -Iinclude -Isrc -D_GNU_SOURCE -fsanitize=address,undefined \ "$t" build/san/*.o -lpthread -o "build/san/$name" "./build/san/$name" done - name: Build and run under ThreadSanitizer run: | # TSan needs personality(ADDR_NO_RANDOMIZE) to disable ASLR for # itself; some containerized runners (including this project's # own registered Gitea runner, confirmed empirically, not just # hypothesized — see CONTRIBUTING.md and CLAUDE.md) block that # syscall outright via their default seccomp profile, in which # case every TSan binary fails identically with `FATAL: # ThreadSanitizer: unexpected memory mapping`, regardless of # PackFS's own correctness. Treating that exact, specific # failure signature as fatal would make CI permanently red for # a reason that has nothing to do with the code under test — so # this step distinguishes it from a real finding (a genuine data # race, a crash, or any other failure) rather than either # blanket-ignoring TSan failures (which would also hide a real # race) or blanket-failing the build on an environment limitation # this repository doesn't control. mkdir -p build/tsan for f in src/*.c; do cc -std=c11 -Wall -Wextra -O1 -g -fPIC -Iinclude -Isrc -D_GNU_SOURCE \ -fsanitize=thread -c "$f" -o "build/tsan/$(basename "${f%.c}").o" done KNOWN_FLAKE=0 REAL_FAILURE=0 for t in tests/test_*.c; do name=$(basename "${t%.c}") cc -std=c11 -O1 -g -Iinclude -Isrc -D_GNU_SOURCE -fsanitize=thread \ "$t" build/tsan/*.o -lpthread -o "build/tsan/$name" OUT=$("./build/tsan/$name" 2>&1) RC=$? if [ $RC -eq 0 ]; then echo "$OUT" elif echo "$OUT" | grep -q "FATAL: ThreadSanitizer: unexpected memory mapping" \ && ! echo "$OUT" | grep -qE "WARNING: ThreadSanitizer: |SUMMARY: ThreadSanitizer:"; then echo "::warning::$name — known runner limitation (TSan can't start here), not a code finding: $OUT" KNOWN_FLAKE=1 else echo "::error::$name — real ThreadSanitizer failure: $OUT" REAL_FAILURE=1 fi done if [ $REAL_FAILURE -ne 0 ]; then echo "One or more binaries failed ThreadSanitizer for a reason other than the known runner limitation. Failing the build." exit 1 fi if [ $KNOWN_FLAKE -ne 0 ]; then echo "ThreadSanitizer could not run at all on this runner (known limitation, not a code issue) — this step is not treated as a build failure, but TSan verification did NOT happen this run. See CONTRIBUTING.md." fi