From 1a4944e619d3c671e4f90c1d83dd051c021307ce Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 28 Sep 2025 19:33:58 -0600 Subject: [PATCH] More msvcrt, fix loading DLLs in program dir regression --- dll/msvcrt.cpp | 243 +++++++++++++++++++++++++++++++++++++++++++- module_registry.cpp | 32 +++--- 2 files changed, 262 insertions(+), 13 deletions(-) diff --git a/dll/msvcrt.cpp b/dll/msvcrt.cpp index 6a42000..2aa2bdb 100644 --- a/dll/msvcrt.cpp +++ b/dll/msvcrt.cpp @@ -72,6 +72,10 @@ namespace msvcrt { return entries; } + IOBProxy *WIN_ENTRY __iob_func() { + return standardIobEntries(); + } + std::unordered_map &iobMapping() { static std::unordered_map mapping; return mapping; @@ -102,6 +106,15 @@ namespace msvcrt { return stream; } + int WIN_ENTRY _fileno(FILE *stream) { + if (!stream) { + errno = EINVAL; + return -1; + } + FILE *host = mapToHostFile(stream); + return ::fileno(host); + } + void refreshMbCurMax() { mbCurMaxValue = static_cast(MB_CUR_MAX); } @@ -496,6 +509,106 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ int WIN_ENTRY strncmp(const char *lhs, const char *rhs, size_t count) { return ::strncmp(lhs, rhs, count); } + void WIN_ENTRY _exit(int status) { + _Exit(status); + } + + int WIN_ENTRY strcpy_s(char *dest, size_t dest_size, const char *src) { + if (!dest || !src || dest_size == 0) { + return 22; + } + + size_t src_len = ::strlen(src); + if (src_len + 1 > dest_size) { + dest[0] = 0; + return 34; + } + + std::memcpy(dest, src, src_len + 1); + return 0; + } + + int WIN_ENTRY strcat_s(char *dest, size_t numberOfElements, const char *src) { + if (!dest || !src || numberOfElements == 0) { + return 22; + } + + size_t dest_len = ::strlen(dest); + size_t src_len = ::strlen(src); + if (dest_len + src_len + 1 > numberOfElements) { + dest[0] = 0; + return 34; + } + + std::memcpy(dest + dest_len, src, src_len + 1); + return 0; + } + + int WIN_ENTRY strncpy_s(char *dest, size_t dest_size, const char *src, size_t count) { + constexpr size_t TRUNCATE = static_cast(-1); + constexpr int STRUNCATE = 80; + + if (!dest || dest_size == 0) { + return 22; + } + + if (!src) { + dest[0] = 0; + return count == 0 ? 0 : 22; + } + + if (count == 0) { + dest[0] = 0; + return 0; + } + + if (count == TRUNCATE) { + size_t src_len = ::strlen(src); + if (src_len + 1 > dest_size) { + size_t copy_len = dest_size > 0 ? dest_size - 1 : 0; + if (copy_len > 0) { + std::memcpy(dest, src, copy_len); + } + dest[copy_len] = '\0'; + return STRUNCATE; + } + std::memcpy(dest, src, src_len + 1); + return 0; + } + + size_t src_len = ::strlen(src); + size_t copy_len = count < src_len ? count : src_len; + if (copy_len >= dest_size) { + dest[0] = 0; + return 34; + } + + if (copy_len > 0) { + std::memcpy(dest, src, copy_len); + } + dest[copy_len] = '\0'; + return 0; + } + + char *WIN_ENTRY _strdup(const char *strSource) { + if (!strSource) { + return nullptr; + } + + size_t length = ::strlen(strSource); + auto *copy = static_cast(std::malloc(length + 1)); + if (!copy) { + return nullptr; + } + + std::memcpy(copy, strSource, length + 1); + return copy; + } + + unsigned long WIN_ENTRY strtoul(const char *str, char **endptr, int base) { + return ::strtoul(str, endptr, base); + } + void* WIN_ENTRY malloc(size_t size){ return std::malloc(size); } @@ -574,8 +687,28 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ return std::memcmp(lhs, rhs, count); } + void WIN_ENTRY qsort(void *base, size_t num, size_t size, int (*compar)(const void *, const void *)) { + std::qsort(base, num, size, compar); + } + int WIN_ENTRY fflush(FILE *stream) { - return std::fflush(stream); + if (!stream) { + return std::fflush(nullptr); + } + FILE *host = mapToHostFile(stream); + return std::fflush(host); + } + + int WIN_ENTRY vfwprintf(FILE *stream, const uint16_t *format, va_list args) { + FILE *host = mapToHostFile(stream ? stream : stdout); + std::wstring fmt; + if (format) { + for (const uint16_t *ptr = format; *ptr; ++ptr) { + fmt.push_back(static_cast(*ptr)); + } + } + fmt.push_back(L'\0'); + return std::vfwprintf(host, fmt.c_str(), args); } FILE *WIN_ENTRY fopen(const char *filename, const char *mode) { @@ -612,6 +745,10 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ return std::fputws(temp.c_str(), stream); } + int WIN_ENTRY _cputws(const uint16_t *string) { + return fputws(string, stdout); + } + uint16_t* WIN_ENTRY fgetws(uint16_t *buffer, int size, FILE *stream) { if (!buffer || size <= 0) { return nullptr; @@ -994,6 +1131,11 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ abort_and_log("terminate"); } + int WIN_ENTRY _purecall() { + abort_and_log("_purecall"); + return 0; + } + int WIN_ENTRY _except_handler4_common(void *, void *, void *, void *) { DEBUG_LOG("_except_handler4_common\n"); return 0; @@ -1204,6 +1346,42 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ return wstrtol(str, nullptr, 10); } + int WIN_ENTRY _ltoa_s(long value, char *buffer, size_t sizeInChars, int radix) { + if (!buffer || sizeInChars == 0) { + return 22; + } + if (radix < 2 || radix > 36) { + buffer[0] = 0; + return 22; + } + + bool isNegative = (value < 0) && (radix == 10); + uint64_t magnitude = isNegative ? static_cast(-(int64_t)value) : static_cast(static_cast(value)); + char temp[65]; + size_t index = 0; + do { + uint64_t digit = magnitude % static_cast(radix); + temp[index++] = static_cast((digit < 10) ? ('0' + digit) : ('a' + (digit - 10))); + magnitude /= static_cast(radix); + } while (magnitude != 0 && index < sizeof(temp)); + + if (isNegative) { + temp[index++] = '-'; + } + + size_t required = index + 1; // include null terminator + if (required > sizeInChars) { + buffer[0] = 0; + return 34; + } + + for (size_t i = 0; i < index; ++i) { + buffer[i] = temp[index - i - 1]; + } + buffer[index] = '\0'; + return 0; + } + int WIN_ENTRY wcscpy_s(uint16_t *dest, size_t dest_size, const uint16_t *src){ std::string src_str = wideStringToString(src); DEBUG_LOG("wcscpy_s %s\n", src_str.c_str()); @@ -1220,6 +1398,54 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ return 0; } + int WIN_ENTRY swprintf_s(uint16_t *buffer, size_t sizeOfBuffer, const uint16_t *format, ...) { + if (!buffer || sizeOfBuffer == 0 || !format) { + errno = EINVAL; + return EINVAL; + } + std::wstring fmt; + for (const uint16_t *ptr = format; *ptr; ++ptr) { + fmt.push_back(static_cast(*ptr)); + } + fmt.push_back(L'\0'); + std::vector temp(sizeOfBuffer); + va_list args; + va_start(args, format); + int written = std::vswprintf(temp.data(), temp.size(), fmt.c_str(), args); + va_end(args); + if (written < 0 || static_cast(written) >= sizeOfBuffer) { + buffer[0] = 0; + errno = ERANGE; + return ERANGE; + } + for (int i = 0; i <= written; ++i) { + buffer[i] = static_cast(temp[static_cast(i)]); + } + return written; + } + + int WIN_ENTRY swscanf_s(const uint16_t *buffer, const uint16_t *format, ...) { + if (!buffer || !format) { + errno = EINVAL; + return EOF; + } + std::wstring bufW; + for (const uint16_t *ptr = buffer; *ptr; ++ptr) { + bufW.push_back(static_cast(*ptr)); + } + bufW.push_back(L'\0'); + std::wstring fmt; + for (const uint16_t *ptr = format; *ptr; ++ptr) { + fmt.push_back(static_cast(*ptr)); + } + fmt.push_back(L'\0'); + va_list args; + va_start(args, format); + int result = std::vswscanf(bufW.c_str(), fmt.c_str(), args); + va_end(args); + return result; + } + int* WIN_ENTRY _get_osfhandle(int fd){ DEBUG_LOG("STUB: _get_osfhandle %d\n", fd); return (int*)fd; @@ -1457,6 +1683,8 @@ static void *resolveByName(const char *name) { if (strcmp(name, "_commode") == 0) return (void *)&msvcrt::_commode; if (strcmp(name, "__initenv") == 0) return (void *)&msvcrt::__initenv; if (strcmp(name, "__winitenv") == 0) return (void *)&msvcrt::__winitenv; + if (strcmp(name, "__iob_func") == 0) return (void *) msvcrt::__iob_func; + if (strcmp(name, "_exit") == 0) return (void *) msvcrt::_exit; if (strcmp(name, "__p__fmode") == 0) return (void *) msvcrt::__p__fmode; if (strcmp(name, "__p__commode") == 0) return (void *) msvcrt::__p__commode; if (strcmp(name, "_initterm") == 0) return (void *)msvcrt::_initterm; @@ -1472,6 +1700,11 @@ static void *resolveByName(const char *name) { if (strcmp(name, "strlen") == 0) return (void *)msvcrt::strlen; if (strcmp(name, "strcmp") == 0) return (void *)msvcrt::strcmp; if (strcmp(name, "strncmp") == 0) return (void *)msvcrt::strncmp; + if (strcmp(name, "strcpy_s") == 0) return (void *)msvcrt::strcpy_s; + if (strcmp(name, "strcat_s") == 0) return (void *)msvcrt::strcat_s; + if (strcmp(name, "strncpy_s") == 0) return (void *)msvcrt::strncpy_s; + if (strcmp(name, "_strdup") == 0) return (void *)msvcrt::_strdup; + if (strcmp(name, "strtoul") == 0) return (void *)msvcrt::strtoul; if (strcmp(name, "malloc") == 0) return (void*)msvcrt::malloc; if (strcmp(name, "calloc") == 0) return (void*)msvcrt::calloc; if (strcmp(name, "_malloc_crt") == 0) return (void*)msvcrt::_malloc_crt; @@ -1490,6 +1723,7 @@ static void *resolveByName(const char *name) { if (strcmp(name, "memcpy") == 0) return (void*)msvcrt::memcpy; if (strcmp(name, "memmove") == 0) return (void*)msvcrt::memmove; if (strcmp(name, "memcmp") == 0) return (void*)msvcrt::memcmp; + if (strcmp(name, "qsort") == 0) return (void*)msvcrt::qsort; if (strcmp(name, "fflush") == 0) return (void*)msvcrt::fflush; if (strcmp(name, "fopen") == 0) return (void*)msvcrt::fopen; if (strcmp(name, "fseek") == 0) return (void*)msvcrt::fseek; @@ -1498,13 +1732,18 @@ static void *resolveByName(const char *name) { if (strcmp(name, "fgetws") == 0) return (void*)msvcrt::fgetws; if (strcmp(name, "fgetwc") == 0) return (void*)msvcrt::fgetwc; if (strcmp(name, "fputws") == 0) return (void*)msvcrt::fputws; + if (strcmp(name, "_cputws") == 0) return (void*)msvcrt::_cputws; + if (strcmp(name, "vfwprintf") == 0) return (void*)msvcrt::vfwprintf; if (strcmp(name, "_wfopen_s") == 0) return (void*)msvcrt::_wfopen_s; if (strcmp(name, "wcsspn") == 0) return (void*)msvcrt::wcsspn; + if (strcmp(name, "_fileno") == 0) return (void*)msvcrt::_fileno; if (strcmp(name, "_wtol") == 0) return (void*)msvcrt::_wtol; if (strcmp(name, "_wcsupr_s") == 0) return (void*)msvcrt::_wcsupr_s; if (strcmp(name, "_wcslwr_s") == 0) return (void*)msvcrt::_wcslwr_s; if (strcmp(name, "_dup2") == 0) return (void*)msvcrt::_dup2; if (strcmp(name, "_isatty") == 0) return (void*)msvcrt::_isatty; + if (strcmp(name, "swprintf_s") == 0) return (void*)msvcrt::swprintf_s; + if (strcmp(name, "swscanf_s") == 0) return (void*)msvcrt::swscanf_s; if (strcmp(name, "towlower") == 0) return (void*)msvcrt::towlower; if (strcmp(name, "_ftime64_s") == 0) return (void*)msvcrt::_ftime64_s; if (strcmp(name, "_crt_debugger_hook") == 0) return (void*)msvcrt::_crt_debugger_hook; @@ -1514,10 +1753,12 @@ static void *resolveByName(const char *name) { if (strcmp(name, "_except_handler4_common") == 0) return (void*)msvcrt::_except_handler4_common; if (strcmp(name, "_XcptFilter") == 0) return (void*)msvcrt::_XcptFilter; if (strcmp(name, "?terminate@@YAXXZ") == 0) return (void*)msvcrt::terminateShim; + if (strcmp(name, "_purecall") == 0) return (void*)msvcrt::_purecall; if (strcmp(name, "wcsncpy_s") == 0) return (void*)msvcrt::wcsncpy_s; if (strcmp(name, "wcsncat_s") == 0) return (void*)msvcrt::wcsncat_s; if (strcmp(name, "_itow_s") == 0) return (void*)msvcrt::_itow_s; if (strcmp(name, "_wtoi") == 0) return (void*)msvcrt::_wtoi; + if (strcmp(name, "_ltoa_s") == 0) return (void*)msvcrt::_ltoa_s; if (strcmp(name, "wcscpy_s") == 0) return (void*)msvcrt::wcscpy_s; if (strcmp(name, "_get_osfhandle") == 0) return (void*)msvcrt::_get_osfhandle; if (strcmp(name, "_write") == 0) return (void*)msvcrt::_write; diff --git a/module_registry.cpp b/module_registry.cpp index 926f647..645c309 100644 --- a/module_registry.cpp +++ b/module_registry.cpp @@ -234,23 +234,31 @@ std::optional combineAndFind(const std::filesystem::path std::vector collectSearchDirectories(ModuleRegistry ®, bool alteredSearchPath) { std::vector dirs; std::unordered_set seen; - auto addDirectory = [&](const std::filesystem::path &dir) { - if (dir.empty()) - return; - std::error_code ec; - auto canonical = std::filesystem::weakly_canonical(dir, ec); + + auto addDirectory = [&](const std::filesystem::path &dir) { + if (dir.empty()) + return; + std::error_code ec; + auto canonical = std::filesystem::weakly_canonical(dir, ec); if (ec) { canonical = std::filesystem::absolute(dir, ec); } if (ec) return; - if (!std::filesystem::exists(canonical, ec) || ec) - return; - std::string key = stringToLower(canonical.string()); - if (seen.insert(key).second) { - dirs.push_back(canonical); - } - }; + if (!std::filesystem::exists(canonical, ec) || ec) + return; + std::string key = stringToLower(canonical.string()); + if (seen.insert(key).second) { + dirs.push_back(canonical); + } + }; + + if (wibo::argv && wibo::argc > 0 && wibo::argv[0]) { + std::filesystem::path mainBinary = std::filesystem::absolute(wibo::argv[0]); + if (mainBinary.has_parent_path()) { + addDirectory(mainBinary.parent_path()); + } + } if (reg.dllDirectory.has_value()) { addDirectory(*reg.dllDirectory);