diff --git a/src/libs/libC.cpp b/src/libs/libC.cpp index 509c3d261..022229fe0 100644 --- a/src/libs/libC.cpp +++ b/src/libs/libC.cpp @@ -360,75 +360,110 @@ static KYTY_SYSV_ABI double libc_difftime(int64_t time1, int64_t time0) { return std::difftime(static_cast(time1), static_cast(time0)); } -static KYTY_SYSV_ABI std::tm* libc_gmtime(const int64_t* timer) { +struct GuestTm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +static_assert(sizeof(GuestTm) == 36); + +static GuestTm ToGuestTm(const std::tm& time) { + return {time.tm_sec, time.tm_min, time.tm_hour, time.tm_mday, time.tm_mon, + time.tm_year, time.tm_wday, time.tm_yday, time.tm_isdst}; +} + +static std::tm ToHostTm(const GuestTm& time) { + std::tm result {}; + result.tm_sec = time.tm_sec; + result.tm_min = time.tm_min; + result.tm_hour = time.tm_hour; + result.tm_mday = time.tm_mday; + result.tm_mon = time.tm_mon; + result.tm_year = time.tm_year; + result.tm_wday = time.tm_wday; + result.tm_yday = time.tm_yday; + result.tm_isdst = time.tm_isdst; + return result; +} + +static KYTY_SYSV_ABI GuestTm* libc_gmtime(const int64_t* timer) { if (timer == nullptr) { return nullptr; } - thread_local std::tm result {}; + thread_local GuestTm result {}; + std::tm host_result {}; const auto t = static_cast(*timer); #if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS - if (_gmtime64_s(&result, &t) != 0) { + if (_gmtime64_s(&host_result, &t) != 0) { return nullptr; } #else - if (gmtime_r(&t, &result) == nullptr) { + if (gmtime_r(&t, &host_result) == nullptr) { return nullptr; } #endif + result = ToGuestTm(host_result); return &result; } -static KYTY_SYSV_ABI std::tm* libc_localtime(const int64_t* timer) { +static KYTY_SYSV_ABI GuestTm* libc_localtime(const int64_t* timer) { if (timer == nullptr) { return nullptr; } - thread_local std::tm result {}; + thread_local GuestTm result {}; + std::tm host_result {}; const auto t = static_cast(*timer); #if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS - if (_localtime64_s(&result, &t) != 0) { + if (_localtime64_s(&host_result, &t) != 0) { return nullptr; } #else - if (localtime_r(&t, &result) == nullptr) { + if (localtime_r(&t, &host_result) == nullptr) { return nullptr; } #endif + result = ToGuestTm(host_result); return &result; } -static KYTY_SYSV_ABI int64_t libc_mktime(std::tm* timeptr) { +static KYTY_SYSV_ABI int64_t libc_mktime(GuestTm* timeptr) { if (timeptr == nullptr) { return -1; } + auto host_time = ToHostTm(*timeptr); + #if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS - return static_cast(_mktime64(timeptr)); + const auto result = static_cast(_mktime64(&host_time)); #else - return static_cast(std::mktime(timeptr)); + const auto result = static_cast(std::mktime(&host_time)); #endif + + *timeptr = ToGuestTm(host_time); + return result; } static KYTY_SYSV_ABI size_t libc_strftime(char* str, size_t count, const char* format, - const std::tm* timeptr) { + const GuestTm* timeptr) { if (str == nullptr || format == nullptr || timeptr == nullptr) { return 0; } -#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX && !defined(__APPLE__) - // Guest-created tm values do not initialize glibc's tm_zone pointer. - std::tm sanitized = *timeptr; - sanitized.tm_zone = nullptr; - - return std::strftime(str, count, format, &sanitized); -#else - return std::strftime(str, count, format, timeptr); -#endif + const auto host_time = ToHostTm(*timeptr); + return std::strftime(str, count, format, &host_time); } static KYTY_SYSV_ABI void catchReturnFromMain(int status) {