diff options
| author | Ron Yorston <rmy@pobox.com> | 2025-11-26 12:56:11 +0000 |
|---|---|---|
| committer | Ron Yorston <rmy@pobox.com> | 2025-11-26 12:56:11 +0000 |
| commit | 3b2f7ff1e0733c8224d0c6a0632abbbb87e8db91 (patch) | |
| tree | 7c11ad683cb9af3dd4d240d62b7104a0178d0edb | |
| parent | 42c3b212d9f9fe964401ed45b1cfd4b67066fb80 (diff) | |
| download | busybox-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.h | 5 | ||||
| -rw-r--r-- | win32/mingw.c | 17 |
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); | |||
| 328 | int nanosleep(const struct timespec *req, struct timespec *rem); | 328 | int nanosleep(const struct timespec *req, struct timespec *rem); |
| 329 | int clock_gettime(clockid_t clockid, struct timespec *tp); | 329 | int clock_gettime(clockid_t clockid, struct timespec *tp); |
| 330 | int clock_settime(clockid_t clockid, const struct timespec *tp); | 330 | int clock_settime(clockid_t clockid, const struct timespec *tp); |
| 331 | struct 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 | ||
| 1107 | struct 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 | |||
| 1103 | struct tm *localtime_r(const time_t *timep, struct tm *result) | 1118 | struct 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 | ||
