Processed: Re: Bug#444589: strftime(%Y) overflows into the negatives for very positive years: the most positive and the most negative times are 1 second apart

2022-07-07 Thread Debian Bug Tracking System
Processing control commands:

> retitle -1 strftime(%Y) overflows into the negatives for very positive years
Bug #444589 [libc6] strftime("%Y") may produce negative year for positive 
tm_year
Changed Bug title to 'strftime(%Y) overflows into the negatives for very 
positive years' from 'strftime("%Y") may produce negative year for positive 
tm_year'.
> found -1 2.33-7
Bug #444589 [libc6] strftime(%Y) overflows into the negatives for very positive 
years
Marked as found in versions glibc/2.33-7.

-- 
444589: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=444589
Debian Bug Tracking System
Contact ow...@bugs.debian.org with problems



Bug#444589: strftime(%Y) overflows into the negatives for very positive years: the most positive and the most negative times are 1 second apart

2022-07-07 Thread наб
Control: retitle -1 strftime(%Y) overflows into the negatives for very positive 
years
Control: found -1 2.33-7

Under TZ=UTC0, the most positive and most negative times glibc
accepts (i.e. "doesn't NULL, EOVERFLOW for") are
   67768036191676799 (0x00F0C2AB7C54A97F)
  -67768040609740800 (0xFF0F3D537C550800)
which are, respectively
   2147485547-12-31 23:59:59
  -2147481748-01-01 00:00:00
however, glibc strftime() apparently forgets to widen the intermediate
representation, because strftime("%F %T") yields, respectively:
  -2147481749-12-31 23:59:59
  -2147481748-01-01 00:00:00
these are 1 second apart, not ~2^32 years.

As expected, 2147481748+1900 is 0x8000`,
and  2147485547-1900 is 0x7FFF`.

Measured via
-- >8 --
#include 
#include 
#include 
#include 

int main(int, const char ** argv) {
std::setlocale(LC_ALL, "");
auto fmt = argv[1] ?: "no format!";
struct timespec ts {};
if(argv[1] && argv[2])
ts.tv_sec = strtoll(argv[2], nullptr, 0);
else
clock_gettime(CLOCK_REALTIME, &ts);
char buf[4096];
std::strftime(buf, sizeof(buf), fmt, localtime(&ts.tv_sec));
std::puts(buf);
}
-- >8 --

Which produces (notably, coreutils date does /not/ have this issue):
-- >8 --
$ TZ=UTC0 date +'%F %T'   -d@67768036191676799
+2147485547-12-31 23:59:59
$ TZ=UTC0 date +'%F %T'  -d@-67768040609740800
-2147481748-01-01 00:00:00
$ TZ=UTC0 ./strdate '%F %T'  67768036191676799
-2147481749-12-31 23:59:59
$ TZ=UTC0 ./strdate '%F %T' -67768040609740800
-2147481748-01-01 00:00:00
-- >8 --

I can reproduce this on bullseye and sid (2.33-7);
substituting experimental (2.34) glibc unrelatedly segfaults.

Best,
наб


signature.asc
Description: PGP signature