diff --git a/.gitea/workflows/gitea-build.yaml b/.gitea/workflows/gitea-build.yaml index 73ab746..1812398 100644 --- a/.gitea/workflows/gitea-build.yaml +++ b/.gitea/workflows/gitea-build.yaml @@ -30,18 +30,6 @@ jobs: - name: Test run: just test - - name: Debug Segfault - if: failure() - run: | - uname -a - cat /etc/os-release || true - clang --version - ulimit -a - free -h || true - SUDO=""; command -v sudo >/dev/null && SUDO=sudo - $SUDO apt-get install -y --no-install-recommends gdb >/dev/null - gdb -batch -ex run -ex bt -ex "info registers" build/tests - - name: Build run: just release diff --git a/AGENTS.md b/AGENTS.md index efe0811..d53314d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,7 +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. 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. -9. **CI's `build` job segfaults on `odin test`** (exit 139) on the self-hosted runner, even running alone — reproduces every push so far. Does not reproduce locally or in a plain `ubuntu:24.04` container with the same Odin version, so it's specific to the runner's actual job image/environment, not the test code. Under investigation; see the `Debug Segfault` diagnostic step in `gitea-build.yaml`. +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 ``` diff --git a/justfile b/justfile index 8c10784..16d3969 100644 --- a/justfile +++ b/justfile @@ -28,6 +28,11 @@ check: # Run the test suite (single-threaded: the tests share the memory game's global state) test: mkdir -p {{build_dir}} + # 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. + ulimit -s 8192 odin test tests -vet -define:ODIN_TEST_THREADS=1 -out:{{build_dir}}/tests # Optimized native build into build//, with the assets it needs at runtime