mktime_utc(): save and restore errno when using timegm().

At least two timegm() implementations, and possibly more, can change
errno even if they succeed.  Save and restore errno, so the "we have
timegm()" implementation of mktime_utc() leaves errno alone, just as the
"we don't have timegm()" implementation does.

This should address the problem mentioned in !11954.
This commit is contained in:
Guy Harris 2023-09-06 00:35:03 -07:00
parent 9e8d63f71e
commit 0ddea7d1e1
1 changed files with 25 additions and 3 deletions

View File

@ -30,9 +30,8 @@
time_t
mktime_utc(struct tm *tm)
{
#ifndef HAVE_TIMEGM
time_t retval;
#ifndef HAVE_TIMEGM
static const int days_before[] =
{
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
@ -57,7 +56,30 @@ mktime_utc(struct tm *tm)
return retval;
#else
return timegm(tm);
int save_errno;
/*
* If passed a struct tm for 2013-03-01 00:00:00, both
* macOS and FreeBSD timegm() return the epoch time
* value for 2013-03-01 00:00:00 UTC, but also set
* errno to EOVERFLOW. This may be true of other
* implementations based on the tzcode reference
* impelementation of timegm().
*
* The macOS and FreeBSD documentation for timegm() neither
* commit to leaving errno alone nor commit to setting it
* to a particular value.
*
* The code we use if we don't have timegm() doesn't
* set errno.
*
* We save and restore errno, so our callers don't need to
* worry about errno getting overwritten.
*/
save_errno = errno;
retval = timegm(tm);
errno = save_errno;
return retval;
#endif /* !HAVE_TIMEGM */
}