diff options
| author | 2026-11-05 10:00:32 +0100 | |
|---|---|---|
| committer | 2026-11-05 10:00:32 +0100 | |
| commit | 51f471432715f7a1880d38c135ce41182b4dc78e (patch) | |
| tree | 131610d91ca3672b7eb6499d6ab778c4bba51636 /src | |
| parent | 5f22030bf57d2f0c78eb26b9778fd3180cfb70f5 (diff) | |
| download | libplist-51f471432715f7a1880d38c135ce41182b4dc78e.tar.gz libplist-51f471432715f7a1880d38c135ce41182b4dc78e.tar.bz2 | |
time64: fix signed overflow for extreme years in gmtime64_r()
IS_LEAP() computed `tm_year + 1900` in int arithmetic, which overflows
for dates around year 2^31 (hit via check_tm() when writing dates).
Cast to Year (64-bit) in IS_LEAP(). Also make gmtime64_r() return NULL
with EOVERFLOW when the calendar year (tm_year + 1900) does not fit in
an int; the previous check compared tm_year with itself and could never
fail. This avoids strftime() wrapping the year in the output, and
callers fall back to their existing default date string.
Credit to OSSFuzz
Diffstat (limited to 'src')
| -rw-r--r-- | src/time64.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/src/time64.c b/src/time64.c index 218088e..6a9218c 100644 --- a/src/time64.c +++ b/src/time64.c @@ -45,6 +45,7 @@ gmtime64_r() is a 64-bit equivalent of gmtime_r(). #include <string.h> #include <time.h> #include <errno.h> +#include <limits.h> #include "time64.h" #include "time64_limits.h" @@ -125,7 +126,7 @@ static const char dow_year_start[SOLAR_CYCLE_LENGTH] = { #define CHEAT_DAYS (1199145600 / 24 / 60 / 60) #define CHEAT_YEARS 108 -#define IS_LEAP(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0) +#define IS_LEAP(n) ((!(((Year)(n) + 1900) % 400) || (!(((Year)(n) + 1900) % 4) && (((Year)(n) + 1900) % 100))) != 0) #define WRAP(a,b,m) ((a) = ((a) < 0 ) ? ((b)--, (a) + (m)) : (a)) #ifdef USE_SYSTEM_LOCALTIME @@ -649,7 +650,8 @@ struct TM *gmtime64_r (const Time64_T *in_time, struct TM *p) } p->tm_year = year; - if( p->tm_year != year ) { + /* The calendar year (tm_year + 1900) must also fit in an int, e.g. for strftime() */ + if( p->tm_year != year || year > (Year)INT_MAX - 1900 || year < (Year)INT_MIN ) { #ifdef EOVERFLOW errno = EOVERFLOW; #endif |
