From 0fa9a2f7e04c3b78b27d85c05dd86f4ef7975701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Thu, 15 Oct 2026 15:44:19 +0000 Subject: [PATCH 1/3] Release v1.3.0 Bump STACKMAN_VERSION and the README banner, and record the changes since 1.2.5 in the changelog. The release tag is not created here. --- CHANGELOG.md | 27 +++++++++++++++++++++++++-- README.md | 2 +- stackman/stackman.h | 6 +++--- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49f2c42..e234cb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.3.0] - 2026-10-15 + ### Added -- FreeBSD, OpenBSD and NetBSD (amd64, `sysv_amd64` ABI) are built and tested on every commit by a new `build and test bsd` workflow. +- `armhf`, a 32-bit ARM hard-float ABI (AAPCS-VFP). `__ARM_PCS_VFP` selects it. Soft-float stays `arm32`. CI and the release archive include `lib/armhf`. +- `docs/platform-abi.md`, the current contract for switching and register spills. `docs/abi-register-audit.md` remains the historical record of that audit. +- `test_09` checks that the caller's rounding mode survives `stackman_switch`, including a switch onto a saved stack. Soft-float `arm32` does not spill `FPSCR`, and the test expects the callback's mode to remain. +- FreeBSD, OpenBSD and NetBSD (amd64, `sysv_amd64` ABI) are built and tested on every commit by a `build and test bsd` workflow. + +### Changed +- `stackman_switch` spills floating-point control and status state and reloads it after the restore callback. `stackman_call` does not touch those registers. +- `armhf` spills the whole `FPSCR`. +- `aarch64` and `darwin_arm64` spill `FPCR` and `FPSR`. +- `win_arm64` spills `FPSR` as well as `FPCR`. +- `riscv64` spills the whole `fcsr`. +- `sysv_i386` spills the x87 control word. `win_x64` spills `MXCSR`. +- `win_x86` spills the x87 control word and `MXCSR`, so older compilers that emit x87 and current MSVC, which emits SSE2, each keep their rounding mode. +- Softfp (`-mfloat-abi=softfp`) is not a supported platform. That build selects `arm32` and does not preserve `FPSCR`. +- CI test steps stop after one minute. ### Fixed +- RISC-V `stackman_call` leaves a null stack unchanged and passes the previous stack pointer to the callback. +- Windows ARM64 no longer uses the live TEB register `x18` as a scratch in `stackman_switch` or `stackman_call`. +- AArch64 `stackman_switch` keeps the frame pointer attached across a stack switch, and the unwind info covers the `FPCR` slot. - ABI detection now works on the BSDs: `tools/abiname.sh` used a `mktemp` template with three `X`s, which BSD `mktemp(1)` rejects. +### Removed +- Leftover Windows ARM32 sources, Visual Studio configurations, and `lib/win_arm`. Version 1.0.0 had already dropped that platform. + ## [1.2.5] - 2026-06-23 ### Changed @@ -142,7 +164,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - GitHub Actions CI for automated building and testing - Visual Studio project files (VS2017, VS2019, VS2022) -[Unreleased]: https://github.com/stackless-dev/stackman/compare/v1.2.5...HEAD +[Unreleased]: https://github.com/stackless-dev/stackman/compare/v1.3.0...HEAD +[1.3.0]: https://github.com/stackless-dev/stackman/releases/tag/v1.3.0 [1.2.5]: https://github.com/stackless-dev/stackman/releases/tag/v1.2.5 [1.2.4]: https://github.com/stackless-dev/stackman/releases/tag/v1.2.4 [1.2.3]: https://github.com/stackless-dev/stackman/releases/tag/v1.2.3 diff --git a/README.md b/README.md index 2d74611..999c87e 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ ║ ║ ║ Do you have a stack? Stackman is here to help. ║ ║ ║ -║ v1.2.5 • 11 platforms • Stack switching simplified ║ +║ v1.3.0 • 11 platforms • Stack switching simplified ║ ║ ║ ╚══════════════════════════════════════════════════════════════╝ ``` diff --git a/stackman/stackman.h b/stackman/stackman.h index 5a0d7b1..47e2f55 100644 --- a/stackman/stackman.h +++ b/stackman/stackman.h @@ -4,11 +4,11 @@ /* Version information */ #define STACKMAN_VERSION_MAJOR 1 -#define STACKMAN_VERSION_MINOR 2 -#define STACKMAN_VERSION_PATCH 5 +#define STACKMAN_VERSION_MINOR 3 +#define STACKMAN_VERSION_PATCH 0 /* Version as a string */ -#define STACKMAN_VERSION "1.2.5" +#define STACKMAN_VERSION "1.3.0" /* Version as a single number for comparisons (MMmmpp: Major, minor, patch) */ #define STACKMAN_VERSION_NUMBER ((STACKMAN_VERSION_MAJOR * 10000) + \ From 183747b1783597856fe5832409e05d69e8ef016d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Thu, 15 Oct 2026 15:59:00 +0000 Subject: [PATCH 2/3] Report the Windows test fault instead of a bare exit code. The x64 test.exe run exits 1 with no assertion text and no test names. stdout is fully buffered on that pipe, and PowerShell turns any native failure into exit code 1. The test now prints each name unbuffered and logs the exception code. The Windows step runs under cmd and prints that process exit code. --- .github/workflows/buildcommit.yml | 7 +++- tests/test.c | 56 +++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/.github/workflows/buildcommit.yml b/.github/workflows/buildcommit.yml index 0fe9f48..07c1348 100644 --- a/.github/workflows/buildcommit.yml +++ b/.github/workflows/buildcommit.yml @@ -163,7 +163,12 @@ jobs: - name: test if: ${{ matrix.native == 'yes' }} timeout-minutes: 1 - run: vs2022\${{matrix.folder}}\Debug\test.exe + shell: cmd + run: | + vs2022\${{matrix.folder}}\Debug\test.exe + set RC=%ERRORLEVEL% + echo test.exe exit %RC% + exit /b %RC% - name: Upload build artifacts uses: actions/upload-artifact@v7.0.0 with: diff --git a/tests/test.c b/tests/test.c index 9a16401..248b92c 100644 --- a/tests/test.c +++ b/tests/test.c @@ -7,6 +7,51 @@ #include #include +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include + +/* Name of the test currently running, so a fault names itself. + * stdout from a crashed process is lost when it is fully buffered. */ +static const char *current_test; + +static LONG WINAPI test_crash(EXCEPTION_POINTERS *info) +{ + EXCEPTION_RECORD *rec = info->ExceptionRecord; + + fprintf(stderr, "exception 0x%08lx at %p during %s", + rec->ExceptionCode, rec->ExceptionAddress, + current_test ? current_test : "startup"); + if (rec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && + rec->NumberParameters >= 2) { + fprintf(stderr, " %s %p", + rec->ExceptionInformation[0] ? "write" : "read", + (void *)rec->ExceptionInformation[1]); + } + fprintf(stderr, "\n"); + fflush(stderr); + return EXCEPTION_CONTINUE_SEARCH; +} +#endif + +static void test_startup(void) +{ + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); +#ifdef _WIN32 + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); + AddVectoredExceptionHandler(1, test_crash); +#endif +} + +static void test_enter(const char *name) +{ +#ifdef _WIN32 + current_test = name; +#endif + printf("%s\n", name); +} + /* Soft-float arm32 does not spill FPSCR. Softfp selects that assembly. */ #if defined(__arm__) && !defined(__aarch64__) && !defined(__ARM_PCS_VFP) #define STACKMAN_ROUND_ISOLATED 0 @@ -567,25 +612,36 @@ void test_09(void *stack_marker) int main(int argc, char*argv[]) { int stack_marker = 0; + + test_startup(); + test_enter("test_01"); test_01(); printf("test_01 ok\n"); + test_enter("test_02"); test_02((void*)&stack_marker); printf("test_02 ok\n"); + test_enter("test_03"); test_03((void*)&stack_marker); printf("test_03 ok\n"); #ifdef TEST_04 + test_enter("test_04"); test_04(); printf("test_04 ok\n"); + test_enter("test_05"); test_05(); printf("test_05 ok\n"); #endif + test_enter("test_06"); test_06(); printf("test_06 ok\n"); + test_enter("test_07"); test_07(); printf("test_07 ok\n"); + test_enter("test_08"); test_08(); printf("test_08 ok\n"); + test_enter("test_09"); test_09((void*)&stack_marker); printf("test_09 ok\n"); return 0; From c6fa6c657e191df8dd01520f9a2c2270a99f1b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Thu, 15 Oct 2026 18:13:33 +0000 Subject: [PATCH 3/3] Note the x64 test stack fix in the 1.3.0 changelog. The stack enlargement itself is on master. This records it with the other changes since 1.2.5. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e234cb9..45aae06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - CI test steps stop after one minute. ### Fixed +- `test_04` allocates 8KB for the `stackman_call` stack. Two MSVC Debug (`/ZI`) frames of the recursive callback overflowed a 1KB block into the heap header, so the x64 test failed intermittently. - RISC-V `stackman_call` leaves a null stack unchanged and passes the previous stack pointer to the callback. - Windows ARM64 no longer uses the live TEB register `x18` as a scratch in `stackman_switch` or `stackman_call`. - AArch64 `stackman_switch` keeps the frame pointer attached across a stack switch, and the unwind info covers the `FPCR` slot.