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/CHANGELOG.md b/CHANGELOG.md index 49f2c42..45aae06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,35 @@ 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 +- `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. - 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 +165,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) + \ 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;