Compare commits

5 Commits
Author SHA1 Message Date
SansanandClaude Sonnet 5 f39ed1684b Sequence windows after build to avoid shared action-cache race
Build and Test / build (push) Successful in 22s
Build and Test / windows (push) Successful in 27s
Release / release (push) Successful in 1m45s
Run 136's build job failed immediately (not a segfault) because it
and windows both clone actions/checkout@v4 and actions/cache@v4 into
the same cache directory on the runner at the same time; one job's
git fetch loses the race and ends up with a missing dist/index.js.
needs: build serializes them so they don't race on that shared cache.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-03 19:43:30 +02:00
SansanandClaude Sonnet 5 f53ec2d71d Fix: ulimit and odin test must be on the same justfile line
Build and Test / build (push) Failing after 4s
Build and Test / windows (push) Successful in 1m9s
just runs each recipe line in its own shell invocation (no shebang on
this recipe), so the previous commit's separate ulimit -s 8192 line
never actually affected the odin test line - CI segfaulted again the
same way. Confirmed fixed in an ubuntu:24.04 container running the
actual `just test` recipe with ulimit -s unlimited set beforehand.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-03 19:41:09 +02:00
SansanandClaude Sonnet 5 06f4e9ed11 Fix CI test segfault: clamp stack ulimit before odin test
Build and Test / build (push) Failing after 19s
Build and Test / windows (push) Successful in 1m34s
Root cause found via gdb backtrace on the runner (thread::pool_init
crashed from main -> testing runner): the CI container sets
`ulimit -s unlimited`, so getrlimit(RLIMIT_STACK) returns RLIM_INFINITY.
core:thread passes that to pthread_attr_setstacksize, pthread_create
fails, and thread.create() returns nil, which core:testing's pool_init
dereferences without a nil check. Reproduced and confirmed fixed in an
ubuntu:24.04 container with the same Odin build. `just test` now clamps
the stack limit before running odin test. Also removes the gdb
diagnostic step added to debug this.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-03 19:35:43 +02:00
SansanandClaude Sonnet 5 0776e8e4b9 Revert runner-contention theory, add gdb diagnostics for the test segfault
Build and Test / build (push) Failing after 25s
Build and Test / windows (push) Successful in 10m28s
The windows job hadn't even started when build's odin test segfaulted
again on its own (run 132), so concurrency wasn't the cause. Add a
Debug Segfault step that runs the already-built test binary under gdb
to get a backtrace, since this doesn't reproduce locally or in a plain
ubuntu:24.04 container with the same Odin build.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-03 18:02:11 +02:00
SansanandClaude Sonnet 5 458f0edccb Sequence windows after build job to avoid CI runner contention
Build and Test / build (push) Failing after 23s
Build and Test / windows (push) Skipped
Both jobs land on the same self-hosted runner. Run 129 segfaulted
odin test in build while windows was mid (uncached) SDK download/
splat at the same time; odin check passed and the test suite
reproduces fine in isolation, so this is resource contention from
running concurrently for the first time, not a code or toolchain bug.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-03 15:56:42 +02:00
3 changed files with 15 additions and 2 deletions

No files matched your search

+7 -1
View File
@@ -33,8 +33,14 @@ jobs:
- name: Build - name: Build
run: just release run: just release
# Cross-compiles for Windows so link breakages show up before a release # Cross-compiles for Windows so link breakages show up before a release.
# Runs after `build`: both jobs clone the same cached actions/checkout and
# actions/cache repos into one shared directory on the runner, and starting
# them at the same time can race on that clone/fetch - one job then gets a
# missing or corrupted action and fails immediately (seen on run 136, not
# related to the odin test fix above). Sequencing avoids the race.
windows: windows:
needs: build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repository - name: Checkout Repository
+1
View File
@@ -38,6 +38,7 @@ Commands (see `justfile`): `just run`, `just check`, `just test`, `just package
6. **Windows builds are cross-compiled**: Odin can't link Windows binaries on Linux, so `just windows` builds objects with `-build-mode:obj` and links with `lld-link` against an xwin SDK. The VC runtime is linked statically; only Windows system DLLs are needed. New Odin core usage can need new import libs (e.g. `ole32.lib` for `os.user_data_dir`); the CI `windows` job catches this. Not yet tested on a real Windows machine. 6. **Windows builds are cross-compiled**: Odin can't link Windows binaries on Linux, so `just windows` builds objects with `-build-mode:obj` and links with `lld-link` against an xwin SDK. The VC runtime is linked statically; only Windows system DLLs are needed. New Odin core usage can need new import libs (e.g. `ole32.lib` for `os.user_data_dir`); the CI `windows` job catches this. Not yet tested on a real Windows machine.
7. **Odin constant arrays can't be indexed at runtime**: lookup tables (`DECKS`, `LAYOUTS`, …) are `@(rodata)` globals instead of `::` constants. 7. **Odin constant arrays can't be indexed at runtime**: lookup tables (`DECKS`, `LAYOUTS`, …) are `@(rodata)` globals instead of `::` constants.
8. **Profile memory**: `profile` always allocates from the heap allocator, because the test runner frees each test's allocator afterwards. 8. **Profile memory**: `profile` always allocates from the heap allocator, because the test runner frees each test's allocator afterwards.
9. **`odin test` segfaults if the stack rlimit is "unlimited"**: the CI runner's container sets `ulimit -s unlimited`, which makes `getrlimit(RLIMIT_STACK).rlim_cur` come back as `RLIM_INFINITY` (a huge unsigned value). Odin's `core:thread` passes that straight to `pthread_attr_setstacksize`, `pthread_create` then fails, and `thread.create()` returns `nil` - which `core:testing`'s `pool_init` dereferences unconditionally, segfaulting the whole test binary (exit 139) before it prints anything. `just test` works around it with `ulimit -s 8192` before running `odin test`. Upstream Odin bug (core:thread/core:testing don't handle a failed thread creation); not our code.
## File Structure ## File Structure
``` ```
+7 -1
View File
@@ -28,7 +28,13 @@ check:
# Run the test suite (single-threaded: the tests share the memory game's global state) # Run the test suite (single-threaded: the tests share the memory game's global state)
test: test:
mkdir -p {{build_dir}} mkdir -p {{build_dir}}
odin test tests -vet -define:ODIN_TEST_THREADS=1 -out:{{build_dir}}/tests # If the stack rlimit is "unlimited" (RLIM_INFINITY, as some CI/container hosts set it),
# Odin's core:thread passes that straight to pthread_attr_setstacksize, pthread_create
# then fails, and thread.create() returns nil - which core:testing's pool_init
# dereferences unconditionally, segfaulting the whole test binary. Clamp it.
# (One line: just runs each recipe line in its own shell, so a separate
# `ulimit` line wouldn't carry over to the `odin test` line.)
ulimit -s 8192 && odin test tests -vet -define:ODIN_TEST_THREADS=1 -out:{{build_dir}}/tests
# Optimized native build into build/<os>/, with the assets it needs at runtime # Optimized native build into build/<os>/, with the assets it needs at runtime
release: release: