Skip to content

Fix case-arm shadowing UB, tail-loop preemption, and OOM diagnostics #87

Fix case-arm shadowing UB, tail-loop preemption, and OOM diagnostics

Fix case-arm shadowing UB, tail-loop preemption, and OOM diagnostics #87

name: Linux quickstart
# Runs the exact README quickstart on a fresh Ubuntu image. If this
# job is red, the README is lying — fix the README (or the build) before
# pushing. Surfaced after a Linux user filed a review where every README
# step failed; this guards against that regression coming back.
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
quickstart:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install README-listed system dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends \
build-essential libsqlite3-dev libssl-dev zlib1g-dev
- name: Build swc + libswarmrt
run: make swc libswarmrt
- name: Compile-check every documented sw snippet + example
# Tripwire against doc/example drift: every complete ```sw block
# in the docs (those with a `module` + `fun main`) and every
# runnable examples/*.sw must still compile with this swc. A red
# here means a copy-paste-able snippet has rotted out of sync
# with the language — fix the snippet (or the compiler).
run: bash scripts/check_sw_docs.sh
- name: Doctest — documented sw examples must RUN + match their output
# One step beyond compile-checking: every complete ```sw block in
# the docs that carries `# =>` expected-output markers is compiled,
# RUN, and its stdout asserted line-for-line. A red here means a
# doc example claims output the language no longer produces — the
# "docs lie" tripwire. Fix the example, the marker, or the compiler.
run: bash scripts/doctest.sh
- name: Run the README quickstart verbatim
run: |
./bin/swc build examples/counter.sw -o counter
# `counter` is a long-running actor demo — give it a few seconds
# then check it produced the documented output.
timeout 5s ./counter > counter.out || true
grep -q "Count:" counter.out
- name: Run a few more examples
run: |
set -e
./bin/swc build examples/hello.sw -o /tmp/hello
/tmp/hello | grep -q "Hello"
./bin/swc build examples/lambda.sw -o /tmp/lambda
/tmp/lambda > /tmp/lambda.out
test -s /tmp/lambda.out
- name: Run the sw test suite
run: make test-sw
- name: Phase test suite (C-side runtime tests)
# Was not in CI before round 7 — codex review caught that
# multiple phase tests were failing locally while CI stayed
# green. Now we gate on phase 2/3/4/5/6/7/8/9. Phase 4
# (Agent/App/DynSup), phase 5 (StateMachine/PG), and phase 7
# (hot reload multi-process/dead-cleanup) all used to fail
# because sw_spawn_link's "non-parent scheduler" hint was
# silently dropped by sw_spawn_opts; fixed in round 7 by
# adding tls_spawn_override.
run: |
set -e
for p in 2 3 4 5 6 7 8 9 10; do
make test-phase$p
done
- name: GC copy-on-escape gate (ASAN + arena poison)
# Compiles the copy-on-escape stress harness under -fsanitize=address +
# -DSW_ARENA_POISON; a missed deep-copy on any send/spawn/ETS boundary
# surfaces as a use-after-free or a 0xDE-garbage content assert.
run: make gc-stress
- name: GC memory-slope gate (Ownership v2 — bounded escaped memory)
# Proves RECLAMATION, not just safety: peak-RSS growth must stay under
# budget across a 10x scale-up of fixed-concurrency spawns, fixed-depth
# messages, and a long-lived tail-recursive loop. Runs under default and
# single-scheduler so adopt/reset/destroy ordering bugs surface too.
run: |
set -e
make gc-slope
SW_SCHEDULERS=1 make gc-slope
- name: LeakSanitizer lifecycle gate (Phase 2.1 — Linux-only LSan)
# The slope gates catch UNBOUNDED growth; this catches BOUNDED leaks
# under their RSS noise floor. macOS Apple-clang ASAN has no LSan, so
# every other ASAN run uses detect_leaks=0 and is leak-blind — this
# Linux leg is the only real leak assertion in CI. Churns every
# lifecycle owner (timers fired+cancelled, supervisors killed, ETS
# replace/delete, spawns, compound messages), exits cleanly, and LSan
# asserts zero definitely-lost blocks at exit. Proven bidirectional
# (an injected unreachable block fails it). Advisory while it bakes;
# promote to blocking once green across a week of pushes.
continue-on-error: true
run: make lsan-gate
- name: Scheduler-count matrix (Phase 2.2 — suite under S=1 and oversubscribed)
# The default-scheduler run above covers nproc; these legs cover the
# edges. S=1 found a real architecture issue (blocking curl client +
# in-process server deadlocks — the affected tests SKIP below 3
# schedulers, see KNOWN_ISSUES); S=8 oversubscribes the runner's
# cores so cross-scheduler interleavings get exercised. The per-test
# 180s timeout in run_tests.sh turns any future hang into a loud FAIL.
run: |
set -e
SW_SCHEDULERS=1 ./tests/sw/run_tests.sh
SW_SCHEDULERS=1 ./tests/sw/run_conform.sh
SW_SCHEDULERS=8 ./tests/sw/run_tests.sh
SW_SCHEDULERS=8 ./tests/sw/run_conform.sh
- name: Stress test (high-process-count race guard)
# Catches regressions in the high-spawn scheduler/mailbox path.
# The historical ctx-tear race is closed by per-slot generation
# counters + ctx_lock; the later spawn-storm crash cleared on
# native Linux x86_64 May 29, so any miss here is a regression.
run: make stress