[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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



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`0000,
        and  2147485547-1900 is 0x7FFF`FFFF.

Measured via
-- >8 --
#include <cstdio>
#include <clocale>
#include <cstdlib>
#include <ctime>

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,
наб

Attachment: signature.asc
Description: PGP signature


Reply to: