From 6d163a87d99fa477147c9ed325743337e0d4c586 Mon Sep 17 00:00:00 2001 From: Hideki Miyazaki Date: Fri, 4 Sep 2026 14:39:07 -0400 Subject: [PATCH] Fix remaining MinGW build errors in the regress/unit test build apps/wolfssh/common.c declared a CONSOLE_SCREEN_BUFFER_INFO local in ClientSetEcho that nothing ever read; the Windows echo toggling never grew the code that would have used it. Drop the unused declaration. wolfssh/port.h defined WSTRSEP as strsep(), a BSD extension MSVCRT and MinGW do not provide. Add a portable wstrsep() in src/port.c, matching the wstrnstr/wstrncat/wstrdup pattern already used for other missing string functions, and route WSTRSEP through it under USE_WINDOWS_API. tests/regress.c called the two argument POSIX mkdir(path, mode) and setenv()/unsetenv() directly in TestKnownHostsLastEntry. Use the existing WMKDIR macro for the directory creation, and add small TEST_SETENV/TEST_UNSETENV macros backed by _putenv_s() on Windows so the HOME juggling this test does still works there. src/wolfsftp.c had three separate issues in code paths that had never been compiled before this job existed. wolfSSH_SFTP_RecvOpen declared a flagsAndAttrs DWORD that nothing read, since WS_CreateFileA is called with a hardcoded FILE_ATTRIBUTE_NORMAL instead. wolfSSH_SFTP_RecvOpenDir compared a signed loop counter against a sizeof expression while building ssh->driveList, so make the counter word32. wolfSSH_SFTP_Put passed &state->rSz, an int, to ReadFile()'s DWORD* output parameter; read into a local DWORD and copy it into state->rSz afterward, since that field is also assigned from WFREAD() on non-Windows builds. src/wolfterm.c's wolfSSH_DoOSC never used its handle parameter. Mark it with WOLFSSH_UNUSED rather than removing it, since the parameter matches the signature its two call sites already pass and future OSC handling such as window titles is a natural use for it. Verified against a real x86_64-w64-mingw32 cross compiler with a config.h edited to match the sizes and header availability the actual Windows CI run reported (SIZEOF_LONG 4, HAVE_SYS_IOCTL_H undefined, and so on): every file this job compiles builds cleanly under the same -Werror flag set. Also reconfirmed a clean, unmodified Linux build still passes both tests/regress.test and tests/unit.test. --- apps/wolfssh/common.c | 1 - src/port.c | 28 ++++++++++++++++++++++++++++ src/wolfsftp.c | 10 +++++++--- src/wolfterm.c | 2 ++ tests/regress.c | 21 ++++++++++++++++----- wolfssh/port.h | 9 ++++++++- 6 files changed, 61 insertions(+), 10 deletions(-) diff --git a/apps/wolfssh/common.c b/apps/wolfssh/common.c index fd5c1d57..013d8640 100644 --- a/apps/wolfssh/common.c +++ b/apps/wolfssh/common.c @@ -721,7 +721,6 @@ int ClientSetEcho(int type) #else static int echoInit = 0; static DWORD originalTerm; - static CONSOLE_SCREEN_BUFFER_INFO screenOrig; HANDLE stdinHandle = GetStdHandle(STD_INPUT_HANDLE); if (!echoInit) { if (GetConsoleMode(stdinHandle, &originalTerm) == 0) { diff --git a/src/port.c b/src/port.c index bd39b64a..e0bd1aef 100644 --- a/src/port.c +++ b/src/port.c @@ -939,4 +939,32 @@ char* wstrncat(char* s1, const char* s2, size_t n) return NULL; } + +#ifdef USE_WINDOWS_API +/* strsep() equivalent for platforms whose C library does not provide the + * BSD extension (MSVCRT/MinGW). Splits *s1 on the first character found + * in delim, NUL-terminates the token in place, and advances *s1 past it + * (NULL when no delimiter remains). Returns the start of the token, or + * NULL if *s1 was already NULL. */ +char* wstrsep(char** s1, const char* delim) +{ + char* start = *s1; + char* p; + + if (start == NULL) + return NULL; + + for (p = start; *p != '\0'; p++) { + if (WSTRCHR(delim, *p) != NULL) { + *p = '\0'; + *s1 = p + 1; + return start; + } + } + + *s1 = NULL; + return start; +} +#endif /* USE_WINDOWS_API */ + #endif /* WSTRING_USER */ diff --git a/src/wolfsftp.c b/src/wolfsftp.c index 88cca98f..3f1d4824 100644 --- a/src/wolfsftp.c +++ b/src/wolfsftp.c @@ -2622,7 +2622,6 @@ cleanup: word32 idx = 0; DWORD desiredAccess = 0; DWORD creationDisp = 0; - DWORD flagsAndAttrs = 0; int ret = WS_SUCCESS; int rc; int fileHandleOpened = 0; @@ -3037,7 +3036,7 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) DWORD drives, mask; UINT driveType; char driveName[] = " :\\"; - int i; + word32 i; WMEMSET(ssh->driveList, 0, sizeof ssh->driveList); ssh->driveListCount = 0; @@ -10401,11 +10400,16 @@ int wolfSSH_SFTP_Put(WOLFSSH* ssh, char* from, char* to, byte resume, break; /* either at end of file or error */ } #else /* USE_WINDOWS_API */ + /* ReadFile() wants a DWORD* out param; state->rSz is + * an int shared with the WFREAD() branch above. */ + DWORD wRSz = 0; + if (ReadFile(state->fileHandle, state->r, - WOLFSSH_MAX_SFTP_RW, &state->rSz, + WOLFSSH_MAX_SFTP_RW, &wRSz, &state->offset) == 0) { break; /* either at end of file or error */ } + state->rSz = (int)wRSz; #endif /* USE_WINDOWS_API */ } sz = wolfSSH_SFTP_SendWritePacket(ssh, diff --git a/src/wolfterm.c b/src/wolfterm.c index 17512d0f..786cee4d 100644 --- a/src/wolfterm.c +++ b/src/wolfterm.c @@ -374,6 +374,8 @@ static int wolfSSH_DoOSC(WOLFSSH* ssh, WOLFSSH_HANDLE handle, byte* buf, * not saved to escBuf and escState is never set to WS_ESC_OSC, so there is * no resume path. Returning WS_SUCCESS lets the caller advance past the * sequence and reset escState cleanly. */ + WOLFSSH_UNUSED(handle); + if (*idx >= bufSz) { /* missing the OSC command byte, drop the sequence */ return WS_SUCCESS; diff --git a/tests/regress.c b/tests/regress.c index 0873b4ec..db867632 100644 --- a/tests/regress.c +++ b/tests/regress.c @@ -13357,6 +13357,17 @@ static int KnownHostsCheckCapture(const byte* pubKey, word32 pubKeySz, } +/* setenv()/unsetenv() are POSIX and have no MSVCRT equivalent; _putenv_s() + * matches their (name, value) shape and success/failure return closely + * enough for this test's own HOME juggling. */ +#ifdef USE_WINDOWS_API + #define TEST_SETENV(n,v) _putenv_s((n), (v)) + #define TEST_UNSETENV(n) _putenv_s((n), "") +#else + #define TEST_SETENV(n,v) setenv((n), (v), 1) + #define TEST_UNSETENV(n) unsetenv((n)) +#endif + /* known_hosts is a text file and POSIX lets its last line end without a * newline, and a file written on Windows ends its lines with CRLF. Match the * last entry with a trailing newline, without one, and with CRLF line @@ -13421,9 +13432,9 @@ static void TestKnownHostsLastEntry(void) (void)rmdir(homeDir); /* Use a single flag to avoid duplicate errors below. */ - ready = (mkdir(homeDir, 0700) == 0) - && (mkdir(sshDir, 0700) == 0) - && (setenv("HOME", homeDir, 1) == 0); + ready = (WMKDIR(NULL, homeDir, 0700) == 0) + && (WMKDIR(NULL, sshDir, 0700) == 0) + && (TEST_SETENV("HOME", homeDir) == 0); AssertTrue(ready); /* A regression falls through to the "add it to known hosts?" prompt, so @@ -13486,11 +13497,11 @@ static void TestKnownHostsLastEntry(void) } if (savedHome != NULL) { - AssertIntEQ(setenv("HOME", savedHome, 1), 0); + AssertIntEQ(TEST_SETENV("HOME", savedHome), 0); WFREE(savedHome, NULL, 0); } else { - unsetenv("HOME"); + TEST_UNSETENV("HOME"); } (void)remove(hostsPath); diff --git a/wolfssh/port.h b/wolfssh/port.h index 3e4a219d..e8383381 100644 --- a/wolfssh/port.h +++ b/wolfssh/port.h @@ -632,7 +632,6 @@ extern "C" { #define WSTRNCMP(s1,s2,n) strncmp((s1),(s2),(n)) #define WSTRSPN(s1,s2) strspn((s1),(s2)) #define WSTRCSPN(s1,s2) strcspn((s1),(s2)) - #define WSTRSEP(s,d) strsep((s),(d)) #define WSTRCAT(s1,s2) strcat((s1),(s2)) #define WSTRCPY(s1,s2) strcpy((s1),(s2)) @@ -645,6 +644,14 @@ extern "C" { #define WSTRDUP(s,h,t) wstrdup((s),(h),(t)) #define WSTRCHR(s,c) strchr((s),(c)) + #ifndef USE_WINDOWS_API + #define WSTRSEP(s,d) strsep((s),(d)) + #else + /* strsep() is a BSD extension not provided by MSVCRT/MinGW */ + WOLFSSH_API char* wstrsep(char** s1, const char* delim); + #define WSTRSEP(s,d) wstrsep((s),(d)) + #endif + #ifdef USE_WINDOWS_API #define WSTRNCPY(s1,s2,n) strncpy_s((s1),(n),(s2),(n)) #define WSTRNCASECMP(s1,s2,n) _strnicmp((s1),(s2),(n))