Skip to content

Run the Unicorn semantics tests on Windows too - #1456

Open
mahmoudimus wants to merge 3 commits into
JonathanSalwan:dev-v1.0from
mahmoudimus:test/aarch64-semantics-on-windows
Open

Run the Unicorn semantics tests on Windows too#1456
mahmoudimus wants to merge 3 commits into
JonathanSalwan:dev-v1.0from
mahmoudimus:test/aarch64-semantics-on-windows

Conversation

@mahmoudimus

@mahmoudimus mahmoudimus commented Aug 27, 2026

Copy link
Copy Markdown

Stacked on #1457 and #1455. The first two commits here are those PRs; please review
only the third. #1457 fixes a pre-existing CMake 4 failure in the vcpkg workflow;
#1455 is the bug this PR's test change uncovers.

Summary

src/testers/CMakeLists.txt has gated the 39 semantics tests to Linux and Darwin since they were added, with the comment "because the setup is easier." That is no longer true, and the gate was concealing a real Windows-only correctness bug.

Why the reason no longer holds

  • unicorn (2.1.4) and lief (1.0.0) both publish win_amd64 wheels.
  • None of the 27 unicorn_test*.py scripts or the 12 lief-driven ARM32 crypto runners contain anything platform specific. Searching all of them for mmap, fcntl, subprocess, os.uname and platform.system matches only the #! line, and ctest invokes them through ${PYTHON_EXECUTABLE} rather than the shebang.
  • .github/actions/install-triton-deps/windows already runs python -m pip install unicorn lief, so Windows CI has been paying for the dependencies without using them.

Measured

windows-2022 as subject, ubuntu-24.04 as control on an identical configuration — capstone 5.0.7, unicorn 2.1.4, lief 1.0.0, LLVM_INTERFACE=OFF on both, versions confirmed from the job logs:

Leg Result Time
windows-x64 40 / 41 605.6s
ubuntu-24.04 (control) 47 / 47 526.2s

The totals differ because Windows does not register the C++ example tests and adds DummyTest.

38 of the 39 previously-gated tests pass on Windows unchanged. The single failure was:

[KO] fmov s0, #2.0
	v0: 0x40000000 (UC) != 0x40 (TT)

which is the bug fixed by #1455. With it applied, both platforms are green.

Cost and benefit

Roughly ten minutes of Windows CI time. In exchange, the AArch64, ARM32, RISC-V and x86 semantics get cross-validated against a second emulator on Windows.

The Python unit tests cannot substitute for this. They check fixed expected values, so they only catch what someone thought to write down — test_semantics.py and test_emulation.py pass on Windows today and never touch fmov with an immediate. Differential testing against Unicorn is what found this, and it is the only thing in the tree that could have.

The vcpkg workflow has failed on every run since 2026-06-27, on all three
platforms, for any PR that touches the tree:

    CMake Error (install-absolute-destination) at src/libtriton/CMakeLists.txt:378 (install):
      INSTALL command given absolute DESTINATION path:
        /home/runner/work/Triton/Triton/out/install/linux-x64/lib/python3.11/site-packages

Nothing in the repository changed. .github/workflows/vcpkg.yml uses
lukka/get-cmake@latest, which is unpinned, so the runner moved from CMake 3.x
to 4.4.2; CMake 4 promoted install-absolute-destination into the developer
warning category, and CMakePresets.json sets "errors": { "dev": true }.

The prefix was redundant in the first place. In this branch PYTHON_SITE_PACKAGES
is already relative -- the execute_process just above it prints
"lib/pythonX.Y/site-packages" -- and install() resolves a relative DESTINATION
against CMAKE_INSTALL_PREFIX. Prefixing it again only made the path absolute.

Dropping the prefix keeps the destination byte-identical for a normal install
and additionally restores `cmake --install --prefix <other>`, which an absolute
DESTINATION silently ignores.

The other branch of the if() is left alone: it deliberately installs into the
interpreter's real site-packages when no prefix was given, so its absolute path
is intended. It is not reachable from the presets, which always set one.

Verified with CMake 4.4.2 locally: reproduced the error before the change, and
after it the generated cmake_install.cmake records
"${CMAKE_INSTALL_PREFIX}/lib/pythonX.Y/site-packages" -- the same location,
resolved relative to the prefix.
@mahmoudimus
mahmoudimus force-pushed the test/aarch64-semantics-on-windows branch from b029fed to 2ea8067 Compare August 30, 2026 19:46
@mahmoudimus

Copy link
Copy Markdown
Author

Heads-up on the red checks here: they are not caused by this PR.

The failing job is Build VCPKG package, and it has failed on every run of that workflow since 2026-06-27 — including patch-1 on 2026-08-12, which predates this branch. The cause is an absolute install(DESTINATION) in src/libtriton/CMakeLists.txt that only becomes an error on CMake >= 4; the workflow uses lukka/get-cmake@latest, so the runner moved to 4.4.2 on its own and nothing in the repository changed.

The line number moves between runs only because commits above it shift it: 378 on patch-1, 385 here. The statement itself is byte-identical to dev-v1.0.

#1457 fixes it, and this branch is now rebased on top of that so it can go green. Note that the workflow runs on these branches are currently held at action_required pending maintainer approval.

…ndows

Immediate::Immediate(double, size, endianness) byte-swaps when the host and
the emulated platform disagree on byte order. The host side came from:

    #ifdef LITTLE_ENDIAN // provided by CMake

CMake does provide it -- but only to one translation unit:

    set_source_files_properties(utils/softfloat.cpp PROPERTIES COMPILE_DEFINITIONS
        ${CMAKE_CXX_BYTE_ORDER}
    )

CMAKE_CXX_BYTE_ORDER expands to the literal LITTLE_ENDIAN or BIG_ENDIAN, so
utils/softfloat.cpp gets the macro and arch/immediate.cpp never does. What
immediate.cpp actually sees is the POSIX definition, and that does not mean
what the #ifdef assumes:

  * On POSIX, <endian.h> defines LITTLE_ENDIAN and BIG_ENDIAN as named
    constants (1234 and 4321), reaching this file transitively. The macro is
    therefore always defined regardless of the actual byte order, so the test
    is really "am I on POSIX". The correct spelling would have been
    BYTE_ORDER == LITTLE_ENDIAN. It selects the right branch today only
    because every platform this is built on happens to be little-endian.

  * Under MSVC neither header nor per-source definition applies, the macro is
    undefined, and Triton concludes it is running big-endian. Every AArch64
    floating-point immediate is then byte-swapped on a little-endian machine:

        fmov s0, #2.0   ->  0x00000040  (expected 0x40000000)
        fmov s0, #1.0   ->  0x0000803f  (expected 0x3f800000)

Extend the byte order to the whole library rather than one file, via the
existing triton/config.hpp, as TRITON_BIG_ENDIAN. The namespaced name also
avoids colliding with the POSIX LITTLE_ENDIAN/BIG_ENDIAN constants, which a
translation-unit-wide LITTLE_ENDIAN definition would risk.

Introduced in JonathanSalwan#1359.
These have been gated to Linux and Darwin since they were added, with the
comment "because the setup is easier". That is no longer true:

  * unicorn (2.1.4) and lief (1.0.0) both publish win_amd64 wheels;
  * none of the 27 unicorn_test*.py scripts nor the 12 lief-driven ARM32
    crypto runners contain anything platform specific;
  * .github/actions/install-triton-deps/windows already pip-installs both,
    so Windows CI has been paying for the dependencies without using them.

Measured on windows-2022, with ubuntu-24.04 as a control on an identical
configuration (capstone 5.0.7, unicorn 2.1.4, lief 1.0.0): Windows 40/41,
Linux control 47/47. The counts differ because Windows does not register the
C++ example tests. The single Windows failure was UnicornAArch64Semantics on
"fmov s0, #2.0", which is the bug fixed by the preceding commit; with that
fix applied both platforms are green.

Cost is roughly ten minutes of Windows CI time. In exchange the AArch64,
ARM32, RISC-V and x86 semantics are cross-validated against a second emulator
on Windows, which the Python unit tests cannot do -- they check fixed expected
values, so they only catch what someone thought to write down.
@mahmoudimus
mahmoudimus force-pushed the test/aarch64-semantics-on-windows branch from 2ea8067 to 8c30c97 Compare August 30, 2026 20:36
mahmoudimus added a commit to mahmoudimus/Triton that referenced this pull request Aug 30, 2026
…t fixes

Brings in the three commits proposed upstream as JonathanSalwan#1457, JonathanSalwan#1455 and JonathanSalwan#1456:

  * absolute install DESTINATION that CMake >= 4 rejects
  * endianness detection that byte-swapped every AArch64 FP immediate
    on Windows builds
  * the platform gate that hid the differential test which found it
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant