CI / build-and-test (push) Failing after 23s
The real Gitea Actions run on this project's own registered runner just failed exactly as CONTRIBUTING.md already anticipated it might: FATAL: ThreadSanitizer: unexpected memory mapping, the same signature already documented as a sandbox/container seccomp restriction blocking personality(ADDR_NO_RANDOMIZE), which TSan needs to start at all. Build, test suite, and ASan/UBSan all passed -- only the TSan step failed, on an environment issue, not a code issue. Fixed the CI step itself rather than just noting the failure: it now classifies each binary's TSan run as PASS, a known flake (that exact FATAL signature and nothing indicating an actual race was found), or a real failure (anything else -- a genuine data race, a crash, any other error). Only a real failure fails the build. Verified the classification logic locally against four cases (a synthetic real race report, a plain assertion failure, the known flake signature alone, and a clean pass) -- each classified correctly -- and against this sandbox's own six test binaries, all six of which hit the real flake (this sandbox has never been able to run TSan either) and correctly did not fail the build. This does NOT mean TSan verification is happening in CI -- it means CI no longer conflates "TSan couldn't start" with "the build is broken." Updated CONTRIBUTING.md and CLAUDE.md from "whether the runner can execute TSan is unverified" (a hedge) to the now-confirmed fact that it can't, and corrected an overclaim in README.md that the suite is "regularly run under ThreadSanitizer" -- as far as this project has been able to confirm, TSan has not actually completed a run in any environment it's been built in yet, local sandbox or CI. ASan/UBSan remain the real, run, load-bearing sanitizer coverage. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqJpkdJ6Njnt1pw3CbghzB
93 lines
4.3 KiB
YAML
93 lines
4.3 KiB
YAML
# 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
|