From 9515c78603dd8e6ae47d9d8a4c8b4629999a8228 Mon Sep 17 00:00:00 2001 From: o-murphy Date: Thu, 22 Oct 2026 17:07:37 +0300 Subject: [PATCH 1/3] wasm2c: use _addcarry_u64 only on MSVC x64, and test a 64-bit memory with MSVC _addcarry_u64 is an intrinsic of the x64 targets: a module with a 64-bit memory fails to link with MSVC for x86 and ARM64 (LNK2019, unresolved external symbol _addcarry_u64). Fall back to the portable branch there. The problem was not seen because run-spec-wasm2c.py skipped the test whenever memory64 is enabled on Windows. That skip was written for the opt-in --enable-memory64; once memory64 became the default it holds for almost every test, so the C that wasm2c writes was not compiled by cl.exe at all. Remove the skip, add a test of a 64-bit memory, and a CI job that builds wabt for Windows x86 and ARM64 and runs it. --- .github/workflows/build.yml | 26 ++++++++++++++++++++++ src/prebuilt/wasm2c_source_declarations.cc | 2 +- src/template/wasm2c.declarations.c | 2 +- test/wasm2c/add.txt | 2 +- test/wasm2c/check-imports.txt | 2 +- test/wasm2c/export-names.txt | 2 +- test/wasm2c/hello.txt | 2 +- test/wasm2c/minimal.txt | 2 +- test/wasm2c/msvc-compile.txt | 14 ++++++++++++ test/wasm2c/tail-calls.txt | 2 +- 10 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 test/wasm2c/msvc-compile.txt diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b27a17052..4d5261093 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -66,6 +66,32 @@ jobs: run: cmake --build out --target run-c-api-tests - name: tests run: cmake --build out --target run-tests + build-msvc-other-archs: + name: build (windows ${{ matrix.arch }}) + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + include: + - arch: x86 + runner: windows-latest + cmake_arch: Win32 + - arch: arm64 + runner: windows-11-arm + cmake_arch: ARM64 + steps: + - uses: actions/setup-python@v5 + with: + python-version: '3.x' + - uses: actions/checkout@v1 + with: + submodules: true + - name: cmake + run: cmake -S . -B out -A ${{ matrix.cmake_arch }} -DWERROR=ON -Werror=dev -DCMAKE_ERROR_DEPRECATED=OFF -DWABT_RUN_TESTS_ARGS=msvc-compile + - name: build + run: cmake --build out + - name: tests + run: cmake --build out --target run-tests emscripten: name: emscripten runs-on: ubuntu-latest diff --git a/src/prebuilt/wasm2c_source_declarations.cc b/src/prebuilt/wasm2c_source_declarations.cc index d46aa00ba..4217a7e8c 100644 --- a/src/prebuilt/wasm2c_source_declarations.cc +++ b/src/prebuilt/wasm2c_source_declarations.cc @@ -200,7 +200,7 @@ R"w2c_template( if (__builtin_add_overflow(a, b, &ret)) )w2c_template" R"w2c_template( TRAP(OOB); )w2c_template" -R"w2c_template(#elif defined(_MSC_VER) +R"w2c_template(#elif defined(_MSC_VER) && defined(_M_X64) )w2c_template" R"w2c_template( if (_addcarry_u64(0, a, b, &ret)) )w2c_template" diff --git a/src/template/wasm2c.declarations.c b/src/template/wasm2c.declarations.c index a3a3ba3a8..0ebfd12df 100644 --- a/src/template/wasm2c.declarations.c +++ b/src/template/wasm2c.declarations.c @@ -107,7 +107,7 @@ static inline uint64_t checked_add_u64(uint64_t a, uint64_t b) { #if __has_builtin(__builtin_add_overflow) if (__builtin_add_overflow(a, b, &ret)) TRAP(OOB); -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) && defined(_M_X64) if (_addcarry_u64(0, a, b, &ret)) TRAP(OOB); #else diff --git a/test/wasm2c/add.txt b/test/wasm2c/add.txt index 874e765e8..7b06d08ff 100644 --- a/test/wasm2c/add.txt +++ b/test/wasm2c/add.txt @@ -216,7 +216,7 @@ static inline uint64_t checked_add_u64(uint64_t a, uint64_t b) { #if __has_builtin(__builtin_add_overflow) if (__builtin_add_overflow(a, b, &ret)) TRAP(OOB); -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) && defined(_M_X64) if (_addcarry_u64(0, a, b, &ret)) TRAP(OOB); #else diff --git a/test/wasm2c/check-imports.txt b/test/wasm2c/check-imports.txt index 9dedd98de..c93f73917 100644 --- a/test/wasm2c/check-imports.txt +++ b/test/wasm2c/check-imports.txt @@ -241,7 +241,7 @@ static inline uint64_t checked_add_u64(uint64_t a, uint64_t b) { #if __has_builtin(__builtin_add_overflow) if (__builtin_add_overflow(a, b, &ret)) TRAP(OOB); -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) && defined(_M_X64) if (_addcarry_u64(0, a, b, &ret)) TRAP(OOB); #else diff --git a/test/wasm2c/export-names.txt b/test/wasm2c/export-names.txt index bf325a05d..5f045cb7f 100644 --- a/test/wasm2c/export-names.txt +++ b/test/wasm2c/export-names.txt @@ -241,7 +241,7 @@ static inline uint64_t checked_add_u64(uint64_t a, uint64_t b) { #if __has_builtin(__builtin_add_overflow) if (__builtin_add_overflow(a, b, &ret)) TRAP(OOB); -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) && defined(_M_X64) if (_addcarry_u64(0, a, b, &ret)) TRAP(OOB); #else diff --git a/test/wasm2c/hello.txt b/test/wasm2c/hello.txt index e1aebdc92..13bd4228a 100644 --- a/test/wasm2c/hello.txt +++ b/test/wasm2c/hello.txt @@ -250,7 +250,7 @@ static inline uint64_t checked_add_u64(uint64_t a, uint64_t b) { #if __has_builtin(__builtin_add_overflow) if (__builtin_add_overflow(a, b, &ret)) TRAP(OOB); -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) && defined(_M_X64) if (_addcarry_u64(0, a, b, &ret)) TRAP(OOB); #else diff --git a/test/wasm2c/minimal.txt b/test/wasm2c/minimal.txt index ea0ce47fa..c3532508c 100644 --- a/test/wasm2c/minimal.txt +++ b/test/wasm2c/minimal.txt @@ -210,7 +210,7 @@ static inline uint64_t checked_add_u64(uint64_t a, uint64_t b) { #if __has_builtin(__builtin_add_overflow) if (__builtin_add_overflow(a, b, &ret)) TRAP(OOB); -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) && defined(_M_X64) if (_addcarry_u64(0, a, b, &ret)) TRAP(OOB); #else diff --git a/test/wasm2c/msvc-compile.txt b/test/wasm2c/msvc-compile.txt new file mode 100644 index 000000000..7701d594e --- /dev/null +++ b/test/wasm2c/msvc-compile.txt @@ -0,0 +1,14 @@ +;;; TOOL: run-spec-wasm2c +;; Compiles and runs the wasm2c output of a module with a 64-bit memory with the +;; C compiler of the platform, MSVC on Windows: the accesses to a 64-bit memory +;; use checked_add_u64. +(module + (memory i64 1) + (func (export "store-load") (param i64 i32) (result i32) + (i32.store (local.get 0) (local.get 1)) + (i32.load (local.get 0)))) +(assert_return (invoke "store-load" (i64.const 8) (i32.const 42)) (i32.const 42)) +(assert_trap (invoke "store-load" (i64.const 0xffffffffffffffff) (i32.const 1)) "out of bounds memory access") +(;; STDOUT ;;; +2/2 tests passed. +;;; STDOUT ;;) diff --git a/test/wasm2c/tail-calls.txt b/test/wasm2c/tail-calls.txt index c6088790e..e4c7ccd22 100644 --- a/test/wasm2c/tail-calls.txt +++ b/test/wasm2c/tail-calls.txt @@ -239,7 +239,7 @@ static inline uint64_t checked_add_u64(uint64_t a, uint64_t b) { #if __has_builtin(__builtin_add_overflow) if (__builtin_add_overflow(a, b, &ret)) TRAP(OOB); -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) && defined(_M_X64) if (_addcarry_u64(0, a, b, &ret)) TRAP(OOB); #else From 3d6ca47a3f9b6e7c8096c924a45589e262204cef Mon Sep 17 00:00:00 2001 From: o-murphy Date: Thu, 22 Oct 2026 22:46:23 +0300 Subject: [PATCH 2/3] CI: run the existing address64 wasm2c test on Windows x86 and ARM64 instead of a new test --- .github/workflows/build.yml | 2 +- test/wasm2c/msvc-compile.txt | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 test/wasm2c/msvc-compile.txt diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4d5261093..fe172ff50 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -87,7 +87,7 @@ jobs: with: submodules: true - name: cmake - run: cmake -S . -B out -A ${{ matrix.cmake_arch }} -DWERROR=ON -Werror=dev -DCMAKE_ERROR_DEPRECATED=OFF -DWABT_RUN_TESTS_ARGS=msvc-compile + run: cmake -S . -B out -A ${{ matrix.cmake_arch }} -DWERROR=ON -Werror=dev -DCMAKE_ERROR_DEPRECATED=OFF -DWABT_RUN_TESTS_ARGS=address64 - name: build run: cmake --build out - name: tests diff --git a/test/wasm2c/msvc-compile.txt b/test/wasm2c/msvc-compile.txt deleted file mode 100644 index 7701d594e..000000000 --- a/test/wasm2c/msvc-compile.txt +++ /dev/null @@ -1,14 +0,0 @@ -;;; TOOL: run-spec-wasm2c -;; Compiles and runs the wasm2c output of a module with a 64-bit memory with the -;; C compiler of the platform, MSVC on Windows: the accesses to a 64-bit memory -;; use checked_add_u64. -(module - (memory i64 1) - (func (export "store-load") (param i64 i32) (result i32) - (i32.store (local.get 0) (local.get 1)) - (i32.load (local.get 0)))) -(assert_return (invoke "store-load" (i64.const 8) (i32.const 42)) (i32.const 42)) -(assert_trap (invoke "store-load" (i64.const 0xffffffffffffffff) (i32.const 1)) "out of bounds memory access") -(;; STDOUT ;;; -2/2 tests passed. -;;; STDOUT ;;) From c5264482f48b2261274ea505319ea5c75368cf28 Mon Sep 17 00:00:00 2001 From: o-murphy Date: Fri, 23 Oct 2026 00:49:15 +0300 Subject: [PATCH 3/3] CI: say that the Windows x86 and ARM64 jobs run minimal tests --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fe172ff50..8a883366e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -67,7 +67,7 @@ jobs: - name: tests run: cmake --build out --target run-tests build-msvc-other-archs: - name: build (windows ${{ matrix.arch }}) + name: build (windows ${{ matrix.arch }}) (minimal tests) runs-on: ${{ matrix.runner }} strategy: fail-fast: false