aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2025-11-26 12:56:11 +0000
committerRon Yorston <rmy@pobox.com>2025-11-26 12:56:11 +0000
commit3b2f7ff1e0733c8224d0c6a0632abbbb87e8db91 (patch)
tree7c11ad683cb9af3dd4d240d62b7104a0178d0edb
parent42c3b212d9f9fe964401ed45b1cfd4b67066fb80 (diff)
downloadbusybox-w32-3b2f7ff1e0733c8224d0c6a0632abbbb87e8db91.tar.gz
busybox-w32-3b2f7ff1e0733c8224d0c6a0632abbbb87e8db91.tar.bz2
busybox-w32-3b2f7ff1e0733c8224d0c6a0632abbbb87e8db91.zip
win32: avoid failure when localtime() argument is out of range
The implementation of localtime(3) in the Microsoft Windows runtime only accepts arguments between the Unix epoch (1970) and either 2038 or 3000 for 32-bit or 64-bit systems respectively. For values outside those limits it returns a NULL pointer. Unfortunately, upstream BusyBox hardly ever bothers to check the return value. Thus, when a call to stat(2) returned an all-zero FILETIME for a file, the 'stat' applet failed. An all-zero FILETIME represents a date in 1600, which is clearly before the Unix epoch. Add a wrapper to localtime(3) which detects an out-of-range value and returns a valid 'struct tm' for the Unix epoch. This is easier than adding checks on the return value of every call to localtime(3). Adds 32-48 bytes. (GitHub issue #548)
-rw-r--r--include/mingw.h5
-rw-r--r--win32/mingw.c17
2 files changed, 20 insertions, 2 deletions
diff --git a/include/mingw.h b/include/mingw.h
index 0a8d52d84..1dcaabbe1 100644
--- a/include/mingw.h
+++ b/include/mingw.h
@@ -6,7 +6,7 @@
6#if !defined(_WIN64) && __MINGW64_VERSION_MAJOR >= 10 6#if !defined(_WIN64) && __MINGW64_VERSION_MAJOR >= 10
7# define time_t __time64_t 7# define time_t __time64_t
8# define ctime(t) _ctime64(t) 8# define ctime(t) _ctime64(t)
9# define localtime(t) _localtime64(t) 9// localtime is handled in mingw_localtime()
10# define time(t) _time64(t) 10# define time(t) _time64(t)
11# define gmtime(t) _gmtime64(t) 11# define gmtime(t) _gmtime64(t)
12# define mktime(t) _mktime64(t) 12# define mktime(t) _mktime64(t)
@@ -328,6 +328,9 @@ time_t timegm(struct tm *tm);
328int nanosleep(const struct timespec *req, struct timespec *rem); 328int nanosleep(const struct timespec *req, struct timespec *rem);
329int clock_gettime(clockid_t clockid, struct timespec *tp); 329int clock_gettime(clockid_t clockid, struct timespec *tp);
330int clock_settime(clockid_t clockid, const struct timespec *tp); 330int clock_settime(clockid_t clockid, const struct timespec *tp);
331struct tm *mingw_localtime(const time_t *timep);
332
333#define localtime mingw_localtime
331 334
332/* 335/*
333 * sys/stat.h 336 * sys/stat.h
diff --git a/win32/mingw.c b/win32/mingw.c
index f9415f509..01548b3ca 100644
--- a/win32/mingw.c
+++ b/win32/mingw.c
@@ -1100,10 +1100,25 @@ struct tm *gmtime_r(const time_t *timep, struct tm *result)
1100 return result; 1100 return result;
1101} 1101}
1102 1102
1103#undef localtime
1104#if !defined(_WIN64) && __MINGW64_VERSION_MAJOR >= 10
1105# define localtime(t) _localtime64(t)
1106#endif
1107struct tm *mingw_localtime(const time_t *timep)
1108{
1109 struct tm *tm = localtime(timep);
1110 time_t epoch = 0;
1111
1112 if (tm == NULL) {
1113 tm = localtime(&epoch);
1114 }
1115 return tm;
1116}
1117
1103struct tm *localtime_r(const time_t *timep, struct tm *result) 1118struct tm *localtime_r(const time_t *timep, struct tm *result)
1104{ 1119{
1105 /* localtime() in MSVCRT.DLL is thread-safe, but not reentrant */ 1120 /* localtime() in MSVCRT.DLL is thread-safe, but not reentrant */
1106 memcpy(result, localtime(timep), sizeof(struct tm)); 1121 memcpy(result, mingw_localtime(timep), sizeof(struct tm));
1107 return result; 1122 return result;
1108} 1123}
1109 1124