https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=2af1914b6ad673a2041cf94cc8e78e1bdec57a27
commit 2af1914b6ad673a2041cf94cc8e78e1bdec57a27 Author: Jeremy Drake <cyg...@jdrake.com> Date: Wed Jun 25 16:42:08 2025 -0700 Cygwin: testsuite: add a mingw test program to spawn This program is currently meant to test standard file handles and current working directory (since these are settable via posix_spawn), but could be extended to add additional checks if other cygwin-to-win32 process properties need to be tested. Signed-off-by: Jeremy Drake <cyg...@jdrake.com> Diff: --- winsup/testsuite/Makefile.am | 2 +- winsup/testsuite/cygrun.sh | 4 +- winsup/testsuite/mingw/Makefile.am | 7 +- winsup/testsuite/winsup.api/posix_spawn/winchild.c | 130 +++++++++++++++++++++ 4 files changed, 139 insertions(+), 4 deletions(-) diff --git a/winsup/testsuite/Makefile.am b/winsup/testsuite/Makefile.am index 957554a82..03f65d818 100644 --- a/winsup/testsuite/Makefile.am +++ b/winsup/testsuite/Makefile.am @@ -349,7 +349,7 @@ XFAIL_TESTS = \ LOG_COMPILER = $(srcdir)/cygrun.sh export runtime_root=$(abs_builddir)/testinst/bin -export cygrun=$(builddir)/mingw/cygrun +export mingwtestdir=$(builddir)/mingw # Set up things in the Cygwin 'installation' at testsuite/testinst/ to provide # things which tests need to work diff --git a/winsup/testsuite/cygrun.sh b/winsup/testsuite/cygrun.sh index bf1d5cc6b..f1673e4db 100755 --- a/winsup/testsuite/cygrun.sh +++ b/winsup/testsuite/cygrun.sh @@ -11,7 +11,7 @@ export PATH="$runtime_root:${PATH}" if [ "$1" = "./mingw/cygload" ] then windows_runtime_root=$(cygpath -m $runtime_root) - $cygrun "$exe -v -cygwin $windows_runtime_root/cygwin1.dll" + $mingwtestdir/cygrun "$exe -v -cygwin $windows_runtime_root/cygwin1.dll" else - cygdrop $cygrun $exe + cygdrop $mingwtestdir/cygrun $exe fi diff --git a/winsup/testsuite/mingw/Makefile.am b/winsup/testsuite/mingw/Makefile.am index 772e73405..25300a15d 100644 --- a/winsup/testsuite/mingw/Makefile.am +++ b/winsup/testsuite/mingw/Makefile.am @@ -16,7 +16,7 @@ override CC = @MINGW_CC@ override CXX = @MINGW_CXX@ AM_CPPFLAGS = -noinst_PROGRAMS = cygrun cygload +noinst_PROGRAMS = cygrun cygload winchild cygrun_SOURCES = \ ../cygrun.c @@ -24,3 +24,8 @@ cygrun_SOURCES = \ cygload_SOURCES = \ ../winsup.api/cygload.cc cygload_LDFLAGS=-static -Wl,-e,cygloadCRTStartup + +winchild_SOURCES = \ + ../winsup.api/posix_spawn/winchild.c +winchild_LDFLAGS=-municode +winchild_LDADD=-lntdll diff --git a/winsup/testsuite/winsup.api/posix_spawn/winchild.c b/winsup/testsuite/winsup.api/posix_spawn/winchild.c new file mode 100644 index 000000000..6fdfa002c --- /dev/null +++ b/winsup/testsuite/winsup.api/posix_spawn/winchild.c @@ -0,0 +1,130 @@ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <winternl.h> +#include <ctype.h> +#include <stdio.h> + + +int wmain (int argc, wchar_t **argv) +{ + if (argc != 3) + { + fwprintf (stderr, L"Usage: %ls handle expected\n", argv[0]); + return 1; + } + + if (!wcscmp (argv[1], L"CWD")) + { + LPWSTR buffer; + DWORD len = GetCurrentDirectoryW (0, NULL); + if (len == 0) + { + fwprintf (stderr, L"%ls: GetCurrentDirectory failed with error %lu\n", + argv[0], GetLastError ()); + return 2; + } + buffer = malloc (len * sizeof (WCHAR)); + if (GetCurrentDirectoryW (len, buffer) != len - 1) + { + fwprintf (stderr, L"%ls: GetCurrentDirectory failed with error %lu\n", + argv[0], GetLastError ()); + return 2; + } + if (wcscmp (argv[2], buffer)) + { + fwprintf (stderr, L"%ls: CWD '%ls' != expected '%ls'\n", + argv[0], buffer, argv[2]); + free (buffer); + return 4; + } + free (buffer); + } + else if (iswdigit (argv[1][0]) && !argv[1][1]) + { + HANDLE stdhandle; + DWORD nStdHandle; + switch (argv[1][0]) + { + case L'0': + nStdHandle = STD_INPUT_HANDLE; + break; + case L'1': + nStdHandle = STD_OUTPUT_HANDLE; + break; + case L'2': + nStdHandle = STD_ERROR_HANDLE; + break; + default: + fwprintf (stderr, L"%ls: Unknown handle '%ls'\n", argv[0], argv[1]); + return 1; + } + + stdhandle = GetStdHandle (nStdHandle); + if (stdhandle == INVALID_HANDLE_VALUE) + { + fwprintf (stderr, L"%ls: Failed getting standard handle %ls: %lu\n", + argv[0], argv[1], GetLastError ()); + return 2; + } + else if (stdhandle == NULL) + { + if (wcscmp (argv[2], L"<CLOSED>")) + { + fwprintf (stderr, + L"%ls: Handle %ls name '%ls' != expected '%ls'\n", + argv[0], argv[1], L"<CLOSED>", argv[2]); + return 4; + } + } + else + { + LPWSTR buf, win32path; + buf = malloc (65536); + if (!GetFinalPathNameByHandleW (stdhandle, buf, + 65536 / sizeof (WCHAR), + FILE_NAME_OPENED|VOLUME_NAME_DOS)) + { + POBJECT_NAME_INFORMATION pinfo = (POBJECT_NAME_INFORMATION) buf; + DWORD err = GetLastError (); + ULONG len; + NTSTATUS status = NtQueryObject (stdhandle, ObjectNameInformation, + pinfo, 65536, &len); + if (!NT_SUCCESS (status)) + { + fwprintf (stderr, + L"%ls: NtQueryObject for handle %ls failed: 0x%08x\n", + argv[0], argv[1], status); + free (buf); + return 3; + } + + pinfo->Name.Buffer[pinfo->Name.Length / sizeof (WCHAR)] = L'\0'; + win32path = pinfo->Name.Buffer; + } + else + { + static const WCHAR prefix[] = L"\\\\?\\"; + win32path = buf; + if (!wcsncmp (win32path, prefix, + sizeof (prefix) / sizeof (WCHAR) - 1)) + win32path += sizeof (prefix) / sizeof (WCHAR) - 1; + } + + if (wcscmp (win32path, argv[2])) + { + fwprintf (stderr, + L"%ls: Handle %ls name '%ls' != expected '%ls'\n", + argv[0], argv[1], win32path, argv[2]); + free (buf); + return 4; + } + free (buf); + } + } + else + { + fwprintf (stderr, L"%ls: Unknown handle '%ls'\n", argv[0], argv[1]); + return 1; + } + return 0; +}