diff --git a/.github/workflows/portability.yml b/.github/workflows/portability.yml index a5ee4068..ebf511c2 100644 --- a/.github/workflows/portability.yml +++ b/.github/workflows/portability.yml @@ -57,7 +57,8 @@ jobs: cmake -S . -B build -G Ninja cmake --build build --parallel 4 ctest --test-dir build -L 'unit|vendor' --output-on-failure --no-tests=error - python tests/interop.py --self --bin build/bin + objdump -p build/bin/ss-server.exe | sed -n '/DLL Name/p' + python tests/interop.py --self --bin build/bin --isolate-windows-runtime - name: Installed consumers run: | cmake --install build --prefix "$PWD/install" diff --git a/docs/measurements/bundled-binaries-macos-arm64.json b/docs/measurements/bundled-binaries-macos-arm64.json index 33079f16..d7e2a17b 100644 --- a/docs/measurements/bundled-binaries-macos-arm64.json +++ b/docs/measurements/bundled-binaries-macos-arm64.json @@ -1,5 +1,5 @@ { - "commit": "feature/self-contained-portable-c (working tree)", + "commit": "46d3acd9d6b72e088b688c2f84aae5c0466885d8", "platform": "Darwin arm64", "binaries": { "ss-local": { diff --git a/docs/measurements/minimal-binaries-macos-arm64.json b/docs/measurements/minimal-binaries-macos-arm64.json index 6aa37b27..1a57434c 100644 --- a/docs/measurements/minimal-binaries-macos-arm64.json +++ b/docs/measurements/minimal-binaries-macos-arm64.json @@ -1,5 +1,5 @@ { - "commit": "feature/self-contained-portable-c (working tree)", + "commit": "46d3acd9d6b72e088b688c2f84aae5c0466885d8", "platform": "Darwin arm64", "binaries": { "ss-local": { diff --git a/tests/interop.py b/tests/interop.py index a708a1d8..39a413b3 100644 --- a/tests/interop.py +++ b/tests/interop.py @@ -137,7 +137,7 @@ def wait_ready(process, port): @contextlib.contextmanager -def peers(commands, ports): +def peers(commands, ports, environment=None): processes = [] with tempfile.TemporaryDirectory(prefix="ss-interop-") as temp, contextlib.ExitStack() as stack: logs = [] @@ -146,7 +146,7 @@ def peers(commands, ports): path = Path(temp) / f"peer-{index}.log" log = stack.enter_context(path.open("wb")) logs.append(path) - process = subprocess.Popen(command, stdout=log, stderr=subprocess.STDOUT) + process = subprocess.Popen(command, stdout=log, stderr=subprocess.STDOUT, env=environment) processes.append(process) wait_ready(process, port) yield @@ -172,9 +172,18 @@ def main(): parser.add_argument("--method", help="run one cipher") parser.add_argument("--bin", default=os.environ.get("SS_BIN_DIR", "build/bin"), help="program directory") parser.add_argument("--plugin", help="SIP003 fixture executable (requires --self)") + parser.add_argument("--isolate-windows-runtime", action="store_true", + help="remove MSYS2/toolchain DLL directories from child PATH") args = parser.parse_args() if args.plugin and not args.self: parser.error("--plugin requires --self") + environment = None + if args.isolate_windows_runtime: + if os.name != "nt": + parser.error("--isolate-windows-runtime requires Windows") + environment = os.environ.copy() + system_root = environment["SystemRoot"] + environment["PATH"] = os.pathsep.join((system_root, os.path.join(system_root, "System32"))) binary_dir = Path(args.bin).resolve() suffix = ".exe" if os.name == "nt" else "" local, server = [str(binary_dir / (name + suffix)) for name in ("ss-local", "ss-server")] @@ -219,7 +228,7 @@ def main(): elif direction.startswith("Rust client"): commands[1] = [rust_local, "-b", f"127.0.0.1:{local_port}", "-s", f"127.0.0.1:{server_port}", "-k", psk, "-m", method, "-U"] try: - with peers(commands, [server_port, local_port]): + with peers(commands, [server_port, local_port], environment): for marker in markers: deadline = time.monotonic() + 10 while not marker.exists() and time.monotonic() < deadline: diff --git a/tests/test_jconf.c b/tests/test_jconf.c index 00ba8b00..03f2a5f9 100644 --- a/tests/test_jconf.c +++ b/tests/test_jconf.c @@ -9,8 +9,6 @@ #include "test_helpers.h" #ifndef _WIN32 #include -#else -#include #endif int verbose = 0; @@ -151,9 +149,21 @@ test_read_jconf_rejects_out_of_range_int_options(void) fclose(f); #ifdef _WIN32 - const char *args[] = {test_executable, "--read-config", path, NULL}; - intptr_t status = _spawnv(_P_WAIT, test_executable, args); - assert(status > 0); + char command[3 * 4096]; + assert(snprintf(command, sizeof(command), "\"%s\" --read-config \"%s\"", + test_executable, path) < (int)sizeof(command)); + STARTUPINFOA startup = {0}; + PROCESS_INFORMATION child = {0}; + startup.cb = sizeof(startup); + assert(CreateProcessA(test_executable, command, NULL, NULL, FALSE, 0, + NULL, NULL, &startup, &child)); + CloseHandle(child.hThread); + assert(WaitForSingleObject(child.hProcess, 10000) == WAIT_OBJECT_0); + DWORD status; + assert(GetExitCodeProcess(child.hProcess, &status)); + CloseHandle(child.hProcess); + /* FATAL exits with -1, which is a valid nonzero DWORD exit status. */ + assert(status != 0); #else pid_t pid = fork(); assert(pid >= 0);