From b2cdfa7f1eb8408339623d3e783100d1fd096444 Mon Sep 17 00:00:00 2001 From: Huang-Ming Huang Date: Mon, 9 Nov 2026 18:23:11 +0000 Subject: [PATCH 1/4] Fix OC signal-handler chaining for legacy and ignored actions Change-Id: I5c03bce57647708db0d9fb473b310f4099266c56 --- .../sys-vm-oc/chained_signal_handler.hpp | 40 ++++++++++ .../runtimes/sys-vm-oc/executor.cpp | 14 ++-- unittests/sysvmoc_signal_handler_tests.cpp | 77 +++++++++++++++++++ 3 files changed, 122 insertions(+), 9 deletions(-) create mode 100644 libraries/chain/include/sysio/chain/webassembly/sys-vm-oc/chained_signal_handler.hpp create mode 100644 unittests/sysvmoc_signal_handler_tests.cpp diff --git a/libraries/chain/include/sysio/chain/webassembly/sys-vm-oc/chained_signal_handler.hpp b/libraries/chain/include/sysio/chain/webassembly/sys-vm-oc/chained_signal_handler.hpp new file mode 100644 index 0000000000..9ea90e0673 --- /dev/null +++ b/libraries/chain/include/sysio/chain/webassembly/sys-vm-oc/chained_signal_handler.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include + +namespace sysio::chain::sysvmoc { + +/// Retain a previous signal action's calling convention when an OC fault belongs to another handler. +class chained_signal_handler { +public: + chained_signal_handler() = default; + + /// Decode SA_SIGINFO once, retaining only a callable predecessor of the corresponding type. + explicit chained_signal_handler(const struct sigaction& action) noexcept { + if (action.sa_handler == SIG_IGN || action.sa_handler == SIG_DFL) + return; + if (action.sa_flags & SA_SIGINFO) + siginfo_handler = action.sa_sigaction; + else + legacy_handler = action.sa_handler; + } + + /// Invoke the predecessor with its original ABI; false leaves default fault handling to the caller. + bool operator()(int signal, siginfo_t* info, void* context) const { + if (siginfo_handler) { + siginfo_handler(signal, info, context); + return true; + } + if (legacy_handler) { + legacy_handler(signal); + return true; + } + return false; + } + +private: + void (*siginfo_handler)(int, siginfo_t*, void*) = nullptr; + void (*legacy_handler)(int) = nullptr; +}; + +} // namespace sysio::chain::sysvmoc diff --git a/libraries/chain/webassembly/runtimes/sys-vm-oc/executor.cpp b/libraries/chain/webassembly/runtimes/sys-vm-oc/executor.cpp index 7d5eb93c74..f10351c79b 100644 --- a/libraries/chain/webassembly/runtimes/sys-vm-oc/executor.cpp +++ b/libraries/chain/webassembly/runtimes/sys-vm-oc/executor.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -36,7 +37,7 @@ namespace sysio::chain::sysvmoc { static constexpr auto signal_sentinel = 0x4D56534F45534559ul; -static void(*chained_handler)(int,siginfo_t*,void*); +static chained_signal_handler chained_handler; static void segv_handler(int sig, siginfo_t* info, void* ctx) { control_block* cb_in_main_segment; @@ -66,10 +67,8 @@ static void segv_handler(int sig, siginfo_t* info, void* ctx) { siglongjmp(*cb_in_main_segment->jmp, SYSVMOC_EXIT_SEGV); notus: - if(chained_handler) { - chained_handler(sig, info, ctx); + if(chained_handler(sig, info, ctx)) return; - } ::signal(sig, SIG_DFL); ::raise(sig); __builtin_unreachable(); @@ -150,15 +149,12 @@ static intrinsic check_memcpy_params_intrinsic("sysvmoc_internal.check_memcpy_pa struct executor_signal_init { executor_signal_init() { - struct sigaction sig_action, old_sig_action; + struct sigaction sig_action{}, old_sig_action{}; sig_action.sa_sigaction = segv_handler; sigemptyset(&sig_action.sa_mask); sig_action.sa_flags = SA_SIGINFO | SA_NODEFER; sigaction(SIGSEGV, &sig_action, &old_sig_action); - if(old_sig_action.sa_flags & SA_SIGINFO) - chained_handler = old_sig_action.sa_sigaction; - else if(old_sig_action.sa_handler != SIG_IGN && old_sig_action.sa_handler != SIG_DFL) - chained_handler = (void (*)(int,siginfo_t*,void*))old_sig_action.sa_handler; + chained_handler = chained_signal_handler(old_sig_action); } }; diff --git a/unittests/sysvmoc_signal_handler_tests.cpp b/unittests/sysvmoc_signal_handler_tests.cpp new file mode 100644 index 0000000000..cd036cb905 --- /dev/null +++ b/unittests/sysvmoc_signal_handler_tests.cpp @@ -0,0 +1,77 @@ +#include + +#include + +namespace { + +/// Captures arguments from a direct handler invocation without installing process-wide signal actions. +struct handler_observation { + int signal = 0; + siginfo_t* info = nullptr; + void* context = nullptr; +}; +handler_observation observed; + +/// Model a one-argument POSIX handler. +void legacy_handler(int signal) { + observed.signal = signal; +} + +/// Model a three-argument SA_SIGINFO handler. +void siginfo_handler(int signal, siginfo_t* info, void* context) { + observed = {signal, info, context}; +} + +} // namespace + +BOOST_AUTO_TEST_SUITE(sysvmoc_signal_handler_tests) + +/// A legacy handler receives the signal through its declared one-argument ABI. +BOOST_AUTO_TEST_CASE(legacy_action) { + struct sigaction action{}; + action.sa_handler = legacy_handler; + observed = {}; + const sysio::chain::sysvmoc::chained_signal_handler handler(action); + BOOST_CHECK(handler(SIGSEGV, nullptr, nullptr)); + BOOST_CHECK_EQUAL(observed.signal, SIGSEGV); + BOOST_CHECK(observed.info == nullptr); + BOOST_CHECK(observed.context == nullptr); +} + +/// A SA_SIGINFO handler retains all three arguments, including their original addresses. +BOOST_AUTO_TEST_CASE(siginfo_action) { + struct sigaction action{}; + action.sa_flags = SA_SIGINFO; + action.sa_sigaction = siginfo_handler; + siginfo_t info{}; + int context = 0; + observed = {}; + const sysio::chain::sysvmoc::chained_signal_handler handler(action); + BOOST_CHECK(handler(SIGSEGV, &info, &context)); + BOOST_CHECK_EQUAL(observed.signal, SIGSEGV); + BOOST_CHECK(observed.info == &info); + BOOST_CHECK(observed.context == &context); +} + +/// Default, ignored, and absent predecessor actions leave the executor's existing fallback in control. +BOOST_AUTO_TEST_CASE(non_callable_actions) { + using sysio::chain::sysvmoc::chained_signal_handler; + observed = {}; + BOOST_CHECK(!chained_signal_handler{}(SIGSEGV, nullptr, nullptr)); + struct sigaction action{}; + action.sa_handler = SIG_DFL; + BOOST_CHECK(!chained_signal_handler{action}(SIGSEGV, nullptr, nullptr)); + action.sa_handler = SIG_IGN; + BOOST_CHECK(!chained_signal_handler{action}(SIGSEGV, nullptr, nullptr)); + action.sa_flags = SA_SIGINFO; + action.sa_handler = SIG_DFL; + BOOST_CHECK(!chained_signal_handler{action}(SIGSEGV, nullptr, nullptr)); + action.sa_handler = SIG_IGN; + BOOST_CHECK(!chained_signal_handler{action}(SIGSEGV, nullptr, nullptr)); + action = {}; + action.sa_flags = SA_SIGINFO; + BOOST_CHECK(!chained_signal_handler{action}(SIGSEGV, nullptr, nullptr)); + BOOST_CHECK_EQUAL(observed.signal, 0); +} + +BOOST_AUTO_TEST_SUITE_END() From df057efd38d0d6075b96fde474bc45d7b49b4c5c Mon Sep 17 00:00:00 2001 From: Huang-Ming Huang Date: Tue, 10 Nov 2026 20:18:01 +0000 Subject: [PATCH 2/4] Address OC signal-handler review feedback Use sig consistently for handler arguments. Register the runtime-independent signal suite once, exclude it from per-runtime discovery, and keep it in the CI unit-test filter. Change-Id: I4cebf3ce64be3ec8a5a950bd3f81bb894b640236 --- .../webassembly/sys-vm-oc/chained_signal_handler.hpp | 6 +++--- unittests/CMakeLists.txt | 9 +++++++-- unittests/sysvmoc_signal_handler_tests.cpp | 8 ++++---- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/libraries/chain/include/sysio/chain/webassembly/sys-vm-oc/chained_signal_handler.hpp b/libraries/chain/include/sysio/chain/webassembly/sys-vm-oc/chained_signal_handler.hpp index 9ea90e0673..d087cf299c 100644 --- a/libraries/chain/include/sysio/chain/webassembly/sys-vm-oc/chained_signal_handler.hpp +++ b/libraries/chain/include/sysio/chain/webassembly/sys-vm-oc/chained_signal_handler.hpp @@ -20,13 +20,13 @@ class chained_signal_handler { } /// Invoke the predecessor with its original ABI; false leaves default fault handling to the caller. - bool operator()(int signal, siginfo_t* info, void* context) const { + bool operator()(int sig, siginfo_t* info, void* context) const { if (siginfo_handler) { - siginfo_handler(signal, info, context); + siginfo_handler(sig, info, context); return true; } if (legacy_handler) { - legacy_handler(signal); + legacy_handler(sig); return true; } return false; diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 3ad970ea7f..8c3ea707d1 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -82,7 +82,10 @@ endif() # Link and include libsodium from vcpkg ### MARK TEST SUITES FOR EXECUTION ### +# Runtime-independent suites are registered once rather than once per WASM runtime. add_p_test(NAME protocol_feature_digest_unit_test COMMAND unit_test --run_test=protocol_feature_digest_tests --report_level=detailed --log_level=all --color_output) +add_p_test(NAME sysvmoc_signal_handler_unit_test + COMMAND unit_test --run_test=sysvmoc_signal_handler_tests --report_level=detailed --log_level=all --color_output) # One entry per suite per runtime, _unit_test_, discovered from the built executable. # To run unit_test with all log from blockchain displayed, put "--verbose" after "--", i.e. "unit_test -- --verbose". # COST starts the longest suites first, even on a fresh run before ctest has measured them. @@ -90,7 +93,7 @@ boost_test_discover_tests(unit_test NAME @NAME@_unit_test_@RUNTIME@ NAME_STRIP "s$" "_test$" RUNTIMES ${UNIT_TEST_RUNTIMES} - EXCLUDE "^protocol_feature_digest_tests$" # registered above: it does not depend on the runtime + EXCLUDE "^(protocol_feature_digest|sysvmoc_signal_handler)_tests$" # registered above without a runtime ARGS --report_level=detailed --log_level=all --color_output COST_BY_NAME "^(api_part[1-3]|checktime|wasm_part[1-3]|wasm_config_part[1-5])$" 5000 "^(snapshot_part[12]|finality)$" 4000 @@ -124,7 +127,9 @@ add_p_test(NAME fork_switch_undoes_kv_writes_unit_test_sys-vm-kv-map add_test(NAME kv_doc_links_unit_test_check COMMAND python3 ${CMAKE_CURRENT_SOURCE_DIR}/check_kv_doc_test_links.py --unit-test $ ${CMAKE_SOURCE_DIR}/docs/kv-behavior-spec.md ${CMAKE_SOURCE_DIR}/docs/kv-security-audit.md) -set(ctest_tests "'_unit_test_|^protocol_feature_digest_unit_test' -LE wasm_spec_tests -j8") # every unit_test entry +# Include every unit_test entry, including the runtime-independent suites. +set(ctest_tests + "'_unit_test_|^(protocol_feature_digest|sysvmoc_signal_handler)_unit_test$' -LE wasm_spec_tests -j8") ### COVERAGE TESTING ### if(ENABLE_COVERAGE_TESTING) diff --git a/unittests/sysvmoc_signal_handler_tests.cpp b/unittests/sysvmoc_signal_handler_tests.cpp index cd036cb905..6fa7d54217 100644 --- a/unittests/sysvmoc_signal_handler_tests.cpp +++ b/unittests/sysvmoc_signal_handler_tests.cpp @@ -13,13 +13,13 @@ struct handler_observation { handler_observation observed; /// Model a one-argument POSIX handler. -void legacy_handler(int signal) { - observed.signal = signal; +void legacy_handler(int sig) { + observed.signal = sig; } /// Model a three-argument SA_SIGINFO handler. -void siginfo_handler(int signal, siginfo_t* info, void* context) { - observed = {signal, info, context}; +void siginfo_handler(int sig, siginfo_t* info, void* context) { + observed = {sig, info, context}; } } // namespace From 13f62722140583e2cf1d27f46648a19ceddb0b31 Mon Sep 17 00:00:00 2001 From: Huang-Ming Huang Date: Tue, 10 Nov 2026 21:06:38 +0000 Subject: [PATCH 3/4] Fix coverage filter escaping across build generators Drop the redundant trailing anchor from the runtime-independent unit-test filter. The non-VERBATIM coverage command otherwise produces invalid Ninja syntax and an unterminated Make shell quote. Validate the actual coverage command block with Ninja and Unix Makefiles. Change-Id: I631ca2914d7c49c0b40615c20dbe5709ecca532c --- unittests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 8c3ea707d1..4ad08559eb 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -129,7 +129,7 @@ add_test(NAME kv_doc_links_unit_test_check ${CMAKE_SOURCE_DIR}/docs/kv-behavior-spec.md ${CMAKE_SOURCE_DIR}/docs/kv-security-audit.md) # Include every unit_test entry, including the runtime-independent suites. set(ctest_tests - "'_unit_test_|^(protocol_feature_digest|sysvmoc_signal_handler)_unit_test$' -LE wasm_spec_tests -j8") + "'_unit_test_|^(protocol_feature_digest|sysvmoc_signal_handler)_unit_test' -LE wasm_spec_tests -j8") ### COVERAGE TESTING ### if(ENABLE_COVERAGE_TESTING) From 315af30e972a2c10a6a8feabc57f5ccb51be9fdf Mon Sep 17 00:00:00 2001 From: Huang-Ming Huang Date: Tue, 10 Nov 2026 21:51:24 +0000 Subject: [PATCH 4/4] Build eos-vm from a pinned source submodule Change-Id: I6b3db83c4b7b165296728dcfc72b7c78176ba255 --- .gitmodules | 3 + BUILD.md | 6 ++ CLAUDE.md | 4 +- CMakeLists.txt | 4 + README.md | 2 +- cmake/add-sys-vm.cmake | 53 +++++++++++ cmake/dependencies.cmake | 1 - cmake/licenses.cmake | 7 +- cmake/test/sys-vm-submodule-test.cmake | 126 +++++++++++++++++++++++++ libraries/CMakeLists.txt | 7 +- libraries/sys-vm | 1 + vcpkg-configuration.json | 1 - vcpkg.json | 10 -- 13 files changed, 204 insertions(+), 21 deletions(-) create mode 100644 cmake/add-sys-vm.cmake create mode 100644 cmake/test/sys-vm-submodule-test.cmake create mode 160000 libraries/sys-vm diff --git a/.gitmodules b/.gitmodules index 7808bd9b1c..9a22ca63f5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,6 @@ path = vcpkg url = https://github.com/Microsoft/vcpkg.git +[submodule "libraries/sys-vm"] + path = libraries/sys-vm + url = https://github.com/Wire-Network/eos-vm diff --git a/BUILD.md b/BUILD.md index 4809d55315..7e3d2a7930 100644 --- a/BUILD.md +++ b/BUILD.md @@ -20,8 +20,14 @@ git clone --recursive https://github.com/Wire-Network/wire-sysio.git # Enter the repo directory cd wire-sysio + +# Refresh pinned submodules when updating an existing checkout +git submodule update --init --recursive vcpkg libraries/appbase libraries/sys-vm ``` +The eos-vm headers are built from the pinned `libraries/sys-vm` submodule. Softfloat and the other +third-party packages continue to come from vcpkg. + # On Host Machine > **ONLY SUPPORTS:** Ubuntu 24.04 LTS and Ubuntu 25.x (x86_64). diff --git a/CLAUDE.md b/CLAUDE.md index 8b86547bf5..a71e3052cd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -106,7 +106,7 @@ sudo apt-get install -y build-essential binutils ccache cmake curl git ninja-bui openjdk-21-jre-headless # Initialize required submodules -git submodule update --init --recursive vcpkg libraries/appbase +git submodule update --init --recursive vcpkg libraries/appbase libraries/sys-vm # Bootstrap vcpkg ./vcpkg/bootstrap-vcpkg.sh @@ -122,7 +122,7 @@ rebuilds through CDT, `sys-vm-jit`, `sys-vm-oc`, and `native-module` are out of # it keg-only, so its bin directory has to be on PATH for CMake's find_package(Java) to see it. brew install cmake ninja ccache pkgconf autoconf automake libtool openjdk export PATH="$(brew --prefix openjdk)/bin:$PATH" -git submodule update --init --recursive vcpkg libraries/appbase +git submodule update --init --recursive vcpkg libraries/appbase libraries/sys-vm ./vcpkg/bootstrap-vcpkg.sh export BUILD_DIR=$PWD/build/macos-arm64 diff --git a/CMakeLists.txt b/CMakeLists.txt index a7ac639075..7af46b476f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,10 @@ include(boost-test-discovery) add_p_test(NAME boost_test_discovery_test COMMAND ${CMAKE_COMMAND} -DGENERATOR=${CMAKE_GENERATOR} -DCXX=${CMAKE_CXX_COMPILER} -DCONFIG=$ -P ${CMAKE_SOURCE_DIR}/cmake/test/boost-test-discovery-test.cmake) +add_p_test(NAME sys_vm_submodule_test + COMMAND ${CMAKE_COMMAND} -DGENERATOR=${CMAKE_GENERATOR} -DCXX=${CMAKE_CXX_COMPILER} -DCONFIG=$ + -DSOURCE_DIR=${CMAKE_SOURCE_DIR} -DWORK_DIR=${CMAKE_BINARY_DIR}/cmake-test/sys-vm-submodule + -DSOFTFLOAT_DIR=${softfloat_DIR} -P ${CMAKE_SOURCE_DIR}/cmake/test/sys-vm-submodule-test.cmake) set(CLI_CLIENT_EXECUTABLE_NAME clio) set(NODE_EXECUTABLE_NAME nodeop) diff --git a/README.md b/README.md index 3221f6c1fd..91d6c3a909 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ contract debugging are not part of this support tier yet. # it keg-only, so its bin directory has to be on PATH for CMake's find_package(Java) to see it. brew install cmake ninja ccache pkgconf autoconf automake libtool openjdk export PATH="$(brew --prefix openjdk)/bin:$PATH" -git submodule update --init --recursive vcpkg libraries/appbase +git submodule update --init --recursive vcpkg libraries/appbase libraries/sys-vm ./vcpkg/bootstrap-vcpkg.sh cmake -B build/macos-arm64 -S . -G Ninja \ diff --git a/cmake/add-sys-vm.cmake b/cmake/add-sys-vm.cmake new file mode 100644 index 0000000000..c19d4cf9a0 --- /dev/null +++ b/cmake/add-sys-vm.cmake @@ -0,0 +1,53 @@ +# Add the pinned VM without changing Sysio's test, tool, compiler, or installation settings. +function(add_sys_vm_submodule SOURCE_DIRECTORY BINARY_DIRECTORY) + if(NOT EXISTS "${SOURCE_DIRECTORY}/CMakeLists.txt") + message(FATAL_ERROR "Missing sys-vm submodule. Run: git submodule update --init libraries/sys-vm") + endif() + + # The subproject predates CMP0077; normal variables keep its options local to this function. + set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + set(ENABLE_TESTS OFF) + set(ENABLE_TOOLS OFF) + set(ENABLE_CCACHE OFF) + set(ENABLE_PROFILE OFF) + set(ENABLE_GPERFTOOLS OFF) + set(ENABLE_ADDRESS_SANITIZER OFF) + set(ENABLE_UNDEFINED_BEHAVIOR_SANITIZER OFF) + set(ENABLE_INSTALL ON) + set(ENABLE_SOFTFLOAT ON) + set(ENABLE_SOFTFLOAT_INSTALL OFF) + set(FULL_DEBUG_BUILD OFF) + set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "${SYSVM_INSTALL_COMPONENT}") + + # cmake_dependent_option writes the shared cache even with CMP0077 NEW. Preserve the parent choices. + set(dependent_options ENABLE_SPEC_TESTS ENABLE_FUZZ_TESTS + ENABLE_ADDRESS_SANITIZER ENABLE_UNDEFINED_BEHAVIOR_SANITIZER) + foreach(option IN LISTS dependent_options) + set(${option}_was_cached FALSE) + if(DEFINED CACHE{${option}}) + set(${option}_was_cached TRUE) + foreach(property VALUE TYPE HELPSTRING) + get_property(${option}_${property} CACHE ${option} PROPERTY ${property}) + endforeach() + endif() + endforeach() + + # Both projects have a dependencies.cmake; resolve the VM's modules in its own source tree first. + list(PREPEND CMAKE_MODULE_PATH "${SOURCE_DIRECTORY}/cmake") + add_subdirectory("${SOURCE_DIRECTORY}" "${BINARY_DIRECTORY}") + + foreach(option IN LISTS dependent_options) + if(${option}_was_cached) + set(${option} "${${option}_VALUE}" CACHE ${${option}_TYPE} "${${option}_HELPSTRING}" FORCE) + else() + unset(${option} CACHE) + endif() + endforeach() + + # The standalone VM relies on global include paths; expose its headers to build and SDK consumers. + target_include_directories(sys-vm SYSTEM INTERFACE + "$" + "$") + target_compile_features(sys-vm INTERFACE cxx_std_20) + add_library(sys-vm::sys-vm ALIAS sys-vm) +endfunction() diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 2ba2c4e956..2229f29a7a 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -84,7 +84,6 @@ find_package(bn256 CONFIG REQUIRED) find_package(bls12-381 CONFIG REQUIRED) find_package(CURL 8.16.0 CONFIG REQUIRED) -find_package(sys-vm CONFIG REQUIRED) # Allocator overrides - linked per-target by apply_malloc_config (cmake/linker-config.cmake). # vcpkg jemalloc port only ships .a + pkg-config (no CMake config), so find by name when enabled. diff --git a/cmake/licenses.cmake b/cmake/licenses.cmake index d1206663db..7ae45f2c08 100644 --- a/cmake/licenses.cmake +++ b/cmake/licenses.cmake @@ -3,6 +3,7 @@ configure_file(${CMAKE_SOURCE_DIR}/LICENSE.md licenses/sysio/LICENSE.md COPYONLY # In-tree dependency licenses configure_file(${CMAKE_SOURCE_DIR}/libraries/wasm-jit/LICENSE licenses/sysio/LICENSE.wavm COPYONLY) +configure_file(${CMAKE_SOURCE_DIR}/libraries/sys-vm/LICENSE.md licenses/sysio/LICENSE.wire-sys-vm COPYONLY) # vcpkg dependency licenses # Collect copyright files from all vcpkg-installed packages into the licenses directory. @@ -50,6 +51,10 @@ foreach(_dir IN LISTS _installed_dirs) if(_pkg MATCHES "^vcpkg-" OR _pkg STREQUAL "cmake" OR _pkg STREQUAL "doc" OR _pkg STREQUAL "pkgconfig") continue() endif() + # A reused vcpkg installation may retain the old VM port; its license now comes from the submodule. + if(_pkg STREQUAL "wire-sys-vm") + continue() + endif() # Skip if already collected above if(_pkg IN_LIST _vcpkg_packages) continue() @@ -64,4 +69,4 @@ foreach(_dir IN LISTS _installed_dirs) endif() endforeach() endif() -endforeach() \ No newline at end of file +endforeach() diff --git a/cmake/test/sys-vm-submodule-test.cmake b/cmake/test/sys-vm-submodule-test.cmake new file mode 100644 index 0000000000..67a841d42f --- /dev/null +++ b/cmake/test/sys-vm-submodule-test.cmake @@ -0,0 +1,126 @@ +# Exercise the real submodule integration, option isolation, and installed SDK interface. +if(NOT WORK_DIR OR NOT SOURCE_DIR OR NOT SOFTFLOAT_DIR) + message(FATAL_ERROR "WORK_DIR, SOURCE_DIR, and SOFTFLOAT_DIR are required") +endif() +if(NOT GENERATOR) + set(GENERATOR Ninja) +endif() +file(MAKE_DIRECTORY "${WORK_DIR}/source/sentinel-modules" "${WORK_DIR}/consumer") +file(WRITE "${WORK_DIR}/source/sentinel-modules/dependencies.cmake" + "message(FATAL_ERROR \"The VM resolved its parent's dependencies.cmake\")\n") + +set(project [=[ +cmake_minimum_required(VERSION 3.19) +project(vm_submodule_probe CXX) +include(GNUInstallDirs) +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME parent_component) +foreach(option ENABLE_TESTS ENABLE_SPEC_TESTS ENABLE_FUZZ_TESTS ENABLE_TOOLS ENABLE_CCACHE + ENABLE_PROFILE ENABLE_GPERFTOOLS ENABLE_ADDRESS_SANITIZER ENABLE_UNDEFINED_BEHAVIOR_SANITIZER) + set(${option} ON CACHE BOOL "Parent setting that the VM must preserve" FORCE) +endforeach() +get_property(original_launcher GLOBAL PROPERTY RULE_LAUNCH_COMPILE) +list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/sentinel-modules") +set(SYSVM_INSTALL_COMPONENT dev) +include("@SOURCE_DIR@/cmake/add-sys-vm.cmake") +if(NOT VM_SOURCE) + set(VM_SOURCE "@SOURCE_DIR@/libraries/sys-vm") +endif() +add_sys_vm_submodule("${VM_SOURCE}" "${CMAKE_CURRENT_BINARY_DIR}/vm") +foreach(option ENABLE_TESTS ENABLE_SPEC_TESTS ENABLE_FUZZ_TESTS ENABLE_TOOLS ENABLE_CCACHE + ENABLE_PROFILE ENABLE_GPERFTOOLS ENABLE_ADDRESS_SANITIZER ENABLE_UNDEFINED_BEHAVIOR_SANITIZER) + get_property(cached CACHE ${option} PROPERTY VALUE) + if(NOT ${option} OR NOT cached) + message(FATAL_ERROR "The VM changed parent setting ${option}") + endif() +endforeach() +get_property(current_launcher GLOBAL PROPERTY RULE_LAUNCH_COMPILE) +if(NOT CMAKE_CXX_STANDARD EQUAL 23 OR + NOT CMAKE_INSTALL_DEFAULT_COMPONENT_NAME STREQUAL "parent_component" OR + NOT "${current_launcher}" STREQUAL "${original_launcher}") + message(FATAL_ERROR "The VM changed parent compiler or installation settings") +endif() +if(TARGET unit_tests OR TARGET sys_vm_spec_tests OR TARGET sys-vm-interp) + message(FATAL_ERROR "The VM enabled its standalone tests or tools") +endif() +add_executable(vm_probe main.cpp) +target_link_libraries(vm_probe PRIVATE sys-vm::sys-vm) +]=]) +string(CONFIGURE "${project}" project @ONLY) +file(WRITE "${WORK_DIR}/source/CMakeLists.txt" "${project}") +file(WRITE "${WORK_DIR}/source/main.cpp" [=[ +#include +#include +static_assert(sysio::vm::use_softfloat); +/// Verify that both build-tree and installed consumers use the fixed signal disposition handling. +int main() { + auto& previous = sysio::vm::prev_signal_handler; + previous = {}; + previous.sa_handler = SIG_IGN; + previous.sa_flags = SA_SIGINFO; + sysio::vm::chain_previous_signal_handler(SIGILL, nullptr, nullptr); +} +]=]) +file(COPY "${WORK_DIR}/source/main.cpp" DESTINATION "${WORK_DIR}/consumer") +file(WRITE "${WORK_DIR}/consumer/CMakeLists.txt" [=[ +cmake_minimum_required(VERSION 3.19) +project(vm_sdk_probe CXX) +find_package(softfloat CONFIG REQUIRED) +find_package(sys-vm CONFIG REQUIRED PATHS "${VM_PREFIX}/share/sys-vm" NO_DEFAULT_PATH) +add_executable(vm_probe main.cpp) +target_link_libraries(vm_probe PRIVATE sys-vm::sys-vm) +]=]) + +# Keep exact configure/build/install diagnostics for failed integration checks. +function(run_checked name) + execute_process(COMMAND ${ARGN} RESULT_VARIABLE result OUTPUT_VARIABLE output ERROR_VARIABLE error) + file(WRITE "${WORK_DIR}/${name}.log" "${output}${error}") + if(NOT result EQUAL 0) + message(FATAL_ERROR "${name} failed (${result}):\n${output}${error}") + endif() +endfunction() + +set(configure_options -G "${GENERATOR}" "-Dsoftfloat_DIR=${SOFTFLOAT_DIR}" -DCMAKE_BUILD_TYPE=Release) +if(CXX) + list(APPEND configure_options "-DCMAKE_CXX_COMPILER=${CXX}") +endif() +set(config_options "") +if(CONFIG) + list(APPEND configure_options "-DCMAKE_CONFIGURATION_TYPES=${CONFIG}") + set(config_options --config "${CONFIG}") +endif() +run_checked(configure "${CMAKE_COMMAND}" -S "${WORK_DIR}/source" -B "${WORK_DIR}/build" ${configure_options}) +run_checked(build "${CMAKE_COMMAND}" --build "${WORK_DIR}/build" ${config_options}) +run_checked(install-dev "${CMAKE_COMMAND}" --install "${WORK_DIR}/build" ${config_options} + --prefix "${WORK_DIR}/sdk" --component dev) +file(SHA256 "${SOURCE_DIR}/libraries/sys-vm/include/sysio/vm/signals.hpp" source_hash) +file(SHA256 "${WORK_DIR}/sdk/include/sysio/vm/signals.hpp" installed_hash) +if(NOT source_hash STREQUAL installed_hash) + message(FATAL_ERROR "The development package does not contain the pinned VM headers") +endif() +run_checked(install-base "${CMAKE_COMMAND}" --install "${WORK_DIR}/build" ${config_options} + --prefix "${WORK_DIR}/base" --component base) +if(EXISTS "${WORK_DIR}/base/include/sysio/vm") + message(FATAL_ERROR "VM development headers leaked into the base component") +endif() +run_checked(consumer-configure "${CMAKE_COMMAND}" -S "${WORK_DIR}/consumer" -B "${WORK_DIR}/consumer-build" + ${configure_options} "-DVM_PREFIX=${WORK_DIR}/sdk") +run_checked(consumer-build "${CMAKE_COMMAND}" --build "${WORK_DIR}/consumer-build" ${config_options}) +foreach(build IN ITEMS build consumer-build) + set(probe "${WORK_DIR}/${build}/vm_probe") + if(CONFIG AND EXISTS "${WORK_DIR}/${build}/${CONFIG}/vm_probe") + set(probe "${WORK_DIR}/${build}/${CONFIG}/vm_probe") + endif() + run_checked("${build}-run" "${probe}") +endforeach() + +# A checkout without the submodule must fail early with an actionable initialization command. +execute_process(COMMAND "${CMAKE_COMMAND}" -S "${WORK_DIR}/source" -B "${WORK_DIR}/missing-build" + ${configure_options} "-DVM_SOURCE=${WORK_DIR}/missing" + RESULT_VARIABLE result OUTPUT_VARIABLE output ERROR_VARIABLE error) +file(WRITE "${WORK_DIR}/missing-submodule.log" "${output}${error}") +string(REGEX REPLACE "[ \t\r\n]+" " " diagnostic "${output}${error}") +if(result EQUAL 0 OR NOT diagnostic MATCHES "git submodule update --init libraries/sys-vm") + message(FATAL_ERROR "A missing VM submodule did not produce the expected initialization error") +endif() +message(STATUS "VM submodule, SDK consumers, option isolation, and missing-submodule checks passed") diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index e5ad7b7be2..a50cc9a960 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -1,6 +1,8 @@ set(APPBASE_INSTALL_COMPONENT "dev") set(SYSVM_INSTALL_COMPONENT "dev") +include(add-sys-vm) +add_sys_vm_submodule("${CMAKE_CURRENT_SOURCE_DIR}/sys-vm" "${CMAKE_CURRENT_BINARY_DIR}/sys-vm") add_subdirectory(libfc-lite) add_subdirectory(libfc) @@ -18,8 +20,3 @@ add_subdirectory(opp) add_subdirectory(testing) add_subdirectory(version) add_subdirectory(state_history) - -if(sys-vm IN_LIST SYSIO_WASM_RUNTIMES OR sys-vm-jit IN_LIST SYSIO_WASM_RUNTIMES) - find_package(sys-vm REQUIRED) - # add_library(sys-vm ALIAS sys-vm::sys-vm) -endif() diff --git a/libraries/sys-vm b/libraries/sys-vm new file mode 160000 index 0000000000..2c8d4b283b --- /dev/null +++ b/libraries/sys-vm @@ -0,0 +1 @@ +Subproject commit 2c8d4b283b500f56241450bdc60a594455a972d9 diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json index 550955a7ff..b60ce56eb6 100644 --- a/vcpkg-configuration.json +++ b/vcpkg-configuration.json @@ -24,7 +24,6 @@ "secp256k1-internal", "bn256", "bls12-381", - "wire-sys-vm", "aws-sdk-cpp", "aws-c-cal", "s2n", diff --git a/vcpkg.json b/vcpkg.json index 7a2ed1b8ca..aa3bd7ea27 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -50,12 +50,6 @@ "name": "rapidjson", "version>=": "2022-06-28#3" }, - { - "name": "wire-sys-vm", - "features": [ - "softfloat-skip-install" - ] - }, { "name": "nlohmann-json", "version>=": "3.12.0#1" @@ -149,10 +143,6 @@ "name": "softfloat", "version": "3.0.0#3" }, - { - "name": "wire-sys-vm", - "version": "1.2.0#2" - }, { "name": "nlohmann-json", "version": "3.12.0#1"