msvcrt: Adjust _gmtime64_s() accepted time limits.

This commit is contained in:
Paul Gofman 2023-12-08 19:10:07 -06:00 committed by Alexandre Julliard
parent 3985b7c599
commit 16dafed08b
5 changed files with 247 additions and 1 deletions

View file

@ -35,6 +35,8 @@
#include <locale.h>
#define _MAX__TIME64_T (((__time64_t)0x00000007 << 32) | 0x93406FFF)
#ifdef __i386__
#include "pshpack1.h"
struct thiscall_thunk
@ -226,6 +228,10 @@ static wctrans_t (__cdecl *p_wctrans)(const char*);
static wint_t (__cdecl *p_towctrans)(wint_t, wctrans_t);
static int (__cdecl *p_strcmp)(const char *, const char *);
static int (__cdecl *p_strncmp)(const char *, const char *, size_t);
static struct tm* (__cdecl *p_gmtime32)(__time32_t*);
static errno_t (__cdecl *p_gmtime32_s)(struct tm*, __time32_t*);
static struct tm* (__cdecl *p_gmtime64)(__time64_t*);
static errno_t (__cdecl *p_gmtime64_s)(struct tm*, __time64_t*);
/* make sure we use the correct errno */
#undef errno
@ -296,6 +302,10 @@ static BOOL init(void)
p_errno = (void*)GetProcAddress(module, "_errno");
p_wcreate_locale = (void*)GetProcAddress(module, "_wcreate_locale");
p_free_locale = (void*)GetProcAddress(module, "_free_locale");
p_gmtime64 = (void*)GetProcAddress(module, "_gmtime64");
p_gmtime64_s = (void*)GetProcAddress(module, "_gmtime64_s");
p_gmtime32 = (void*)GetProcAddress(module, "_gmtime32");
p_gmtime32_s = (void*)GetProcAddress(module, "_gmtime32_s");
SET(p_wctype, "wctype");
SET(p_fegetenv, "fegetenv");
SET(p_fesetenv, "fesetenv");
@ -1714,6 +1724,73 @@ static void test_strcmp(void)
ok( ret == 0, "wrong ret %d\n", ret );
}
static void test_gmtime64(void)
{
struct tm *ptm, tm;
__time64_t t;
int ret;
t = -1;
memset(&tm, 0xcc, sizeof(tm));
ptm = p_gmtime64(&t);
ok(!!ptm, "got NULL.\n");
ret = p_gmtime64_s(&tm, &t);
ok(!ret, "got %d.\n", ret);
ok(tm.tm_year == 69 && tm.tm_hour == 23 && tm.tm_min == 59 && tm.tm_sec == 59, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
t = -43200;
memset(&tm, 0xcc, sizeof(tm));
ptm = p_gmtime64(&t);
ok(!!ptm, "got NULL.\n");
ret = p_gmtime64_s(&tm, &t);
ok(!ret, "got %d.\n", ret);
ok(tm.tm_year == 69 && tm.tm_hour == 12 && tm.tm_min == 0 && tm.tm_sec == 0, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
ptm = p_gmtime32((__time32_t *)&t);
ok(!!ptm, "got NULL.\n");
memset(&tm, 0xcc, sizeof(tm));
ret = p_gmtime32_s(&tm, (__time32_t *)&t);
ok(!ret, "got %d.\n", ret);
todo_wine_if(tm.tm_year == 69 && tm.tm_hour == 12)
ok(tm.tm_year == 70 && tm.tm_hour == -12 && tm.tm_min == 0 && tm.tm_sec == 0, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
t = -43201;
ptm = p_gmtime64(&t);
ok(!ptm, "got non-NULL.\n");
memset(&tm, 0xcc, sizeof(tm));
ret = p_gmtime64_s(&tm, &t);
ok(ret == EINVAL, "got %d.\n", ret);
ok(tm.tm_year == -1 && tm.tm_hour == -1 && tm.tm_min == -1 && tm.tm_sec == -1, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
ptm = p_gmtime32((__time32_t *)&t);
ok(!ptm, "got NULL.\n");
memset(&tm, 0xcc, sizeof(tm));
ret = p_gmtime32_s(&tm, (__time32_t *)&t);
ok(ret == EINVAL, "got %d.\n", ret);
ok(tm.tm_year == -1 && tm.tm_hour == -1 && tm.tm_min == -1 && tm.tm_sec == -1, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
t = _MAX__TIME64_T + 46800;
memset(&tm, 0xcc, sizeof(tm));
ptm = p_gmtime64(&t);
ok(!!ptm, "got NULL.\n");
ret = p_gmtime64_s(&tm, &t);
ok(!ret, "got %d.\n", ret);
ok(tm.tm_year == 1101 && tm.tm_hour == 20 && tm.tm_min == 59 && tm.tm_sec == 59, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
t = _MAX__TIME64_T + 46801;
ptm = p_gmtime64(&t);
ok(!ptm, "got non-NULL.\n");
memset(&tm, 0xcc, sizeof(tm));
ret = p_gmtime64_s(&tm, &t);
ok(ret == EINVAL, "got %d.\n", ret);
ok(tm.tm_year == -1 && tm.tm_hour == -1 && tm.tm_min == -1 && tm.tm_sec == -1, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
}
START_TEST(msvcr120)
{
if (!init()) return;
@ -1738,4 +1815,5 @@ START_TEST(msvcr120)
test_CurrentContext();
test_StructuredTaskCollection();
test_strcmp();
test_gmtime64();
}

View file

@ -55,6 +55,8 @@ static __time32_t (__cdecl *p_mkgmtime32)(struct tm*);
static struct tm* (__cdecl *p_gmtime32)(__time32_t*);
static struct tm* (__cdecl *p_gmtime)(time_t*);
static errno_t (__cdecl *p_gmtime32_s)(struct tm*, __time32_t*);
static struct tm* (__cdecl *p_gmtime64)(__time64_t*);
static errno_t (__cdecl *p_gmtime64_s)(struct tm*, __time64_t*);
static errno_t (__cdecl *p_strtime_s)(char*,size_t);
static errno_t (__cdecl *p_strdate_s)(char*,size_t);
static errno_t (__cdecl *p_localtime32_s)(struct tm*, __time32_t*);
@ -76,6 +78,8 @@ static void init(void)
p_gmtime32 = (void*)GetProcAddress(hmod, "_gmtime32");
p_gmtime = (void*)GetProcAddress(hmod, "gmtime");
p_gmtime32_s = (void*)GetProcAddress(hmod, "_gmtime32_s");
p_gmtime64 = (void*)GetProcAddress(hmod, "_gmtime64");
p_gmtime64_s = (void*)GetProcAddress(hmod, "_gmtime64_s");
p_mkgmtime32 = (void*)GetProcAddress(hmod, "_mkgmtime32");
p_strtime_s = (void*)GetProcAddress(hmod, "_strtime_s");
p_strdate_s = (void*)GetProcAddress(hmod, "_strdate_s");
@ -208,6 +212,78 @@ static void test_gmtime(void)
}
}
static void test_gmtime64(void)
{
struct tm *ptm, tm;
__time64_t t;
int ret;
t = -1;
memset(&tm, 0xcc, sizeof(tm));
ptm = p_gmtime64(&t);
if (!ptm)
{
skip("Old gmtime64 limits, skipping tests.\n");
return;
}
ok(!!ptm, "got NULL.\n");
ret = p_gmtime64_s(&tm, &t);
ok(!ret, "got %d.\n", ret);
ok(tm.tm_year == 69 && tm.tm_hour == 23 && tm.tm_min == 59 && tm.tm_sec == 59, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
t = -43200;
memset(&tm, 0xcc, sizeof(tm));
ptm = p_gmtime64(&t);
ok(!!ptm, "got NULL.\n");
ret = p_gmtime64_s(&tm, &t);
ok(!ret, "got %d.\n", ret);
ok(tm.tm_year == 69 && tm.tm_hour == 12 && tm.tm_min == 0 && tm.tm_sec == 0, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
ptm = p_gmtime32((__time32_t *)&t);
ok(!!ptm, "got NULL.\n");
memset(&tm, 0xcc, sizeof(tm));
ret = p_gmtime32_s(&tm, (__time32_t *)&t);
ok(!ret, "got %d.\n", ret);
todo_wine_if(tm.tm_year == 69 && tm.tm_hour == 12)
ok(tm.tm_year == 70 && tm.tm_hour == -12 && tm.tm_min == 0 && tm.tm_sec == 0, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
t = -43201;
ptm = p_gmtime64(&t);
ok(!ptm, "got non-NULL.\n");
memset(&tm, 0xcc, sizeof(tm));
ret = p_gmtime64_s(&tm, &t);
ok(ret == EINVAL, "got %d.\n", ret);
ok(tm.tm_year == -1 && tm.tm_hour == -1 && tm.tm_min == -1 && tm.tm_sec == -1, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
ptm = p_gmtime32((__time32_t *)&t);
ok(!ptm, "got NULL.\n");
memset(&tm, 0xcc, sizeof(tm));
ret = p_gmtime32_s(&tm, (__time32_t *)&t);
ok(ret == EINVAL, "got %d.\n", ret);
ok(tm.tm_year == -1 && tm.tm_hour == -1 && tm.tm_min == -1 && tm.tm_sec == -1, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
t = _MAX__TIME64_T + 46800;
memset(&tm, 0xcc, sizeof(tm));
ptm = p_gmtime64(&t);
ok(!!ptm, "got NULL.\n");
ret = p_gmtime64_s(&tm, &t);
ok(!ret, "got %d.\n", ret);
ok(tm.tm_year == 1101 && tm.tm_hour == 20 && tm.tm_min == 59 && tm.tm_sec == 59, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
t = _MAX__TIME64_T + 46801;
ptm = p_gmtime64(&t);
ok(!ptm, "got non-NULL.\n");
memset(&tm, 0xcc, sizeof(tm));
ret = p_gmtime64_s(&tm, &t);
ok(ret == EINVAL, "got %d.\n", ret);
ok(tm.tm_year == -1 && tm.tm_hour == -1 && tm.tm_min == -1 && tm.tm_sec == -1, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
}
static void test_mktime(void)
{
TIME_ZONE_INFORMATION tzinfo;
@ -963,6 +1039,7 @@ START_TEST(time)
test_strftime();
test_ctime();
test_gmtime();
test_gmtime64();
test_mktime();
test_localtime();
test_strdate();

View file

@ -66,6 +66,17 @@ static const int MAX_SECONDS = 60;
static const int MAX_SECONDS = 59;
#endif
#if _MSVCR_VER == 0
#define MIN_GMTIME64_TIME 0
#define MAX_GMTIME64_TIME _MAX__TIME64_T
#elif _MSVCR_VER >= 140
#define MIN_GMTIME64_TIME -43200
#define MAX_GMTIME64_TIME (_MAX__TIME64_T + 1605600)
#else
#define MIN_GMTIME64_TIME -43200
#define MAX_GMTIME64_TIME (_MAX__TIME64_T + 46800)
#endif
static inline BOOL IsLeapYear(int Year)
{
return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0);
@ -457,7 +468,9 @@ int CDECL _gmtime64_s(struct tm *res, const __time64_t *secs)
SYSTEMTIME st;
ULONGLONG time;
if (!res || !secs || *secs < 0 || *secs > _MAX__TIME64_T) {
TRACE("res %p, secs %p (%I64d).\n", res, secs, secs ? *secs : 0);
if (!res || !secs || *secs < MIN_GMTIME64_TIME || *secs > MAX_GMTIME64_TIME) {
if (res) {
write_invalid_msvcrt_tm(res);
}

View file

@ -113,6 +113,8 @@ _se_translator_function __cdecl _set_se_translator(_se_translator_function func)
void** __cdecl __current_exception(void);
int* __cdecl __processing_throw(void);
#define _MAX__TIME64_T (((__time64_t)0x00000007 << 32) | 0x93406FFF)
static void test__initialize_onexit_table(void)
{
_onexit_table_t table, table2;
@ -1632,6 +1634,78 @@ static void test_rewind_i386_abi(void)
}
#endif
static void test_gmtime64(void)
{
struct tm *ptm, tm;
__time64_t t;
int ret;
t = -1;
memset(&tm, 0xcc, sizeof(tm));
ptm = _gmtime64(&t);
ok(!!ptm, "got NULL.\n");
ret = _gmtime64_s(&tm, &t);
ok(!ret, "got %d.\n", ret);
ok(tm.tm_year == 69 && tm.tm_hour == 23 && tm.tm_min == 59 && tm.tm_sec == 59, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
t = -43200;
memset(&tm, 0xcc, sizeof(tm));
ptm = _gmtime64(&t);
ok(!!ptm, "got NULL.\n");
ret = _gmtime64_s(&tm, &t);
ok(!ret, "got %d.\n", ret);
ok(tm.tm_year == 69 && tm.tm_hour == 12 && tm.tm_min == 0 && tm.tm_sec == 0, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
ptm = _gmtime32((__time32_t *)&t);
ok(!!ptm, "got NULL.\n");
memset(&tm, 0xcc, sizeof(tm));
ret = _gmtime32_s(&tm, (__time32_t *)&t);
ok(!ret, "got %d.\n", ret);
todo_wine_if(tm.tm_year == 69 && tm.tm_hour == 12)
ok(tm.tm_year == 70 && tm.tm_hour == -12 && tm.tm_min == 0 && tm.tm_sec == 0, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
t = -43201;
ptm = _gmtime64(&t);
ok(!ptm, "got non-NULL.\n");
memset(&tm, 0xcc, sizeof(tm));
ret = _gmtime64_s(&tm, &t);
ok(ret == EINVAL, "got %d.\n", ret);
ok(tm.tm_year == -1 && tm.tm_hour == -1 && tm.tm_min == -1 && tm.tm_sec == -1, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
ptm = _gmtime32((__time32_t *)&t);
ok(!ptm, "got NULL.\n");
memset(&tm, 0xcc, sizeof(tm));
ret = _gmtime32_s(&tm, (__time32_t *)&t);
ok(ret == EINVAL, "got %d.\n", ret);
ok(tm.tm_year == -1 && tm.tm_hour == -1 && tm.tm_min == -1 && tm.tm_sec == -1, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
t = _MAX__TIME64_T + 1605600;
memset(&tm, 0xcc, sizeof(tm));
ptm = _gmtime64(&t);
ok(!!ptm || broken(!ptm) /* before Win10 1909 */, "got NULL.\n");
if (!ptm)
{
win_skip("Old gmtime64 limits, skipping tests.\n");
return;
}
ret = _gmtime64_s(&tm, &t);
ok(!ret, "got %d.\n", ret);
ok(tm.tm_year == 1101 && tm.tm_hour == 21 && tm.tm_min == 59 && tm.tm_sec == 59, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
t = _MAX__TIME64_T + 1605601;
ptm = _gmtime64(&t);
ok(!ptm, "got non-NULL.\n");
memset(&tm, 0xcc, sizeof(tm));
ret = _gmtime64_s(&tm, &t);
ok(ret == EINVAL, "got %d.\n", ret);
ok(tm.tm_year == -1 && tm.tm_hour == -1 && tm.tm_min == -1 && tm.tm_sec == -1, "got %d, %d, %d, %d.\n",
tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
}
START_TEST(misc)
{
int arg_c;
@ -1677,4 +1751,5 @@ START_TEST(misc)
#if defined(__i386__)
test_rewind_i386_abi();
#endif
test_gmtime64();
}

View file

@ -80,7 +80,10 @@ _ACRTIMP errno_t __cdecl _ctime64_s(char*,size_t,const __time64_t*);
_ACRTIMP double __cdecl _difftime32(__time32_t,__time32_t);
_ACRTIMP double __cdecl _difftime64(__time64_t,__time64_t);
_ACRTIMP struct tm* __cdecl _gmtime32(const __time32_t*);
_ACRTIMP int __cdecl _gmtime32_s(struct tm *res, const __time32_t *secs);
_ACRTIMP struct tm* __cdecl _gmtime64(const __time64_t*);
_ACRTIMP int __cdecl _gmtime64_s(struct tm *res, const __time64_t *secs);
_ACRTIMP struct tm* __cdecl _localtime32(const __time32_t*);
_ACRTIMP errno_t __cdecl _localtime32_s(struct tm*, const __time32_t*);
_ACRTIMP struct tm* __cdecl _localtime64(const __time64_t*);