[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#38958: Timestamp out of range; substituting 2514-05-30 01:53:03.9999
From: |
Mark H Weaver |
Subject: |
bug#38958: Timestamp out of range; substituting 2514-05-30 01:53:03.999999999 |
Date: |
Thu, 03 Sep 2020 15:42:02 -0400 |
Hi,
Ludovic Courtès <ludo@gnu.org> writes:
> The GNU make warnings come from this impenetrable function:
>
> --8<---------------cut here---------------start------------->8---
> FILE_TIMESTAMP
> file_timestamp_cons (const char *fname, time_t stamp, long int ns)
> {
> int offset = ORDINARY_MTIME_MIN + (FILE_TIMESTAMP_HI_RES ? ns : 0);
> FILE_TIMESTAMP s = stamp;
> FILE_TIMESTAMP product = (FILE_TIMESTAMP) s << FILE_TIMESTAMP_LO_BITS;
> FILE_TIMESTAMP ts = product + offset;
>
> if (! (s <= FILE_TIMESTAMP_S (ORDINARY_MTIME_MAX)
> && product <= ts && ts <= ORDINARY_MTIME_MAX))
> {
> char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1];
> const char *f = fname ? fname : _("Current time");
> ts = s <= OLD_MTIME ? ORDINARY_MTIME_MIN : ORDINARY_MTIME_MAX;
> file_timestamp_sprintf (buf, ts);
> OSS (error, NILF,
> _("%s: Timestamp out of range; substituting %s"), f, buf);
> }
>
> return ts;
> }
> --8<---------------cut here---------------end--------------->8---
>
> What’s OLD_MTIME?
>
> --8<---------------cut here---------------start------------->8---
> /* The file does not exist, and we assume that it is older than any
> actual file. */
> #define OLD_MTIME 2
>
> /* The smallest and largest ordinary timestamps. */
> #define ORDINARY_MTIME_MIN (OLD_MTIME + 1)
> --8<---------------cut here---------------end--------------->8---
>
> That would mean that any file with mtime < 3 is considered bogus, but
> then, why wouldn’t things fail on other machines as well?
I spent a bit of time looking at the relevant code in GNU Make. The
special MTIME values of 0, 1, and 2 seem to apply only to GNU Make's
*internal* representation of the timestamp. 'file_timestamp_cons',
which converts a standard POSIX time to the internal representation,
seems to properly handle times near the POSIX epoch by adding
ORDINARY_MTIME_MIN (via 'offset') to the POSIX time, after multiplying
it by 2^30 (if FILE_TIMESTAMP_HI_RES is enabled).
> I’m looking for ideas! :-)
Note that the date printed in the warning (ORDINARY_MTIME_MAX),
represented as a POSIX time (seconds past the epoch), is precisely 2^34
seconds minus one nanosecond.
The problem doesn't seem to be that 'stamp' is too small, because if it
were, then the following line in 'file_timestamp_cons',
ts = s <= OLD_MTIME ? ORDINARY_MTIME_MIN : ORDINARY_MTIME_MAX;
would substitute ORDINARY_MTIME_MIN, which is close to the POSIX epoch,
and the warning message would print a time near 1970, instead of one
near 2514 (ORDINARY_MTIME_MAX).
Rather, it appears that the 'stamp' passed into 'file_timestamp_cons'
was close to or larger than 2^34, which is approximately the largest
timestamp that GNU make supports when FILE_TIMESTAMP is 64 bits and
FILE_TIMESTAMP_HI_RES is enabled.
My guess is that maybe our near-zero timestamps are somewhere being
adjusted downwards by a timezone conversion, using an unsigned integer
type, causing them to wrap around to near the maximum value of that
type.
Note that although 'stamp' usually comes from a file 'mtime' as returned
by stat(2), it can also come from an 'ar' archive member. In
make-4.3/src/remake.c, 'f_mtime' includes the following code:
--8<---------------cut here---------------start------------->8---
member_date = ar_member_date (file->hname);
mtime = (member_date == (time_t) -1
? NONEXISTENT_MTIME
: file_timestamp_cons (file->hname, member_date, 0));
--8<---------------cut here---------------end--------------->8---
Mark