[BZ #23603][BZ #16346]
This fixes some obscure problems with integer overflow.
Although it looks scary, it is almost all a byte-for-byte copy
from Gnulib, and the Gnulib code has been tested reasonably well.
* include/intprops.h: New file, copied from Gnulib.
* include/verify.h, time/mktime-internal.h:
New tiny files, simplified from Gnulib.
* time/mktime.c: Copy from Gnulib. This has the following changes:
Do not include config.h if DEBUG_MKTIME is nonzero.
Include stdbool.h, intprops.h, verify.h.
Include string.h only if needed.
Include stdlib.h on MS-Windows.
Include mktime-internal.h.
(DEBUG_MKTIME): Default to 0, and simplify later uses.
(NEED_MKTIME_INTERNAL, NEED_MKTIME_WINDOWS)
(NEED_MKTIME_WORKING): Give default values to pacify -Wundef,
which glibc uses. Default NEED_MKTIME_WORKING to DEBUG_MKTIME, to
simplify later conditionals; default the others to zero. Use
these conditionals to express only the code needed on the current
platform. In uses of these conditionals, explicitly spell out how
_LIBC affects things, so it’s easier to review from a glibc
viewpoint.
(WRAPV): Remove; no longer needed now that we have
systematic overflow checking.
(my_tzset, __tzset) [!_LIBC]: New function and macro, to better
compartmentalize tzset issues. Move system-dependent tzsettish
code here from mktime.
(verify): Remove; now done by verify.h. All uses changed.
(long_int): Use a more-conservative definition, to avoid
integer overflow.
(SHR): Remove, replacing with ...
(shr): New function, which means we needn’t worry about side
effects in args, and conversion analysis is simpler.
(TYPE_IS_INTEGER, TYPE_TWOS_COMPLEMENT, TYPE_SIGNED, TYPE_MINIMUM)
(TYPE_MAXIMUM, TIME_T_MIN, TIME_T_MAX, TIME_T_MIDPOINT)
(time_t_avg, time_t_add_ok): Remove.
(mktime_min, mktime_max): New constants.
(leapyear, isdst_differ): Use bool for booleans.
(ydhms_diff, guess_time_tm, ranged_convert, __mktime_internal):
Use long_int, not time_t, for mktime differences.
(long_int_avg): New function, replacing time_t_avg.
INT_ADD_WRAPV replaces time_t_add_ok.
(guess_time_tm): 6th arg is now long_int, not time_t const *.
All uses changed.
(convert_time): New function.
(ranged_convert): Use it.
(__mktime_internal): Last arg now points to mktime_offset_t, not
time_t. All uses changed. This is a no-op on glibc, where
mktime_offset_t is always time_t. Use int, not time_t, for UTC
offset guess. Directly check for integer overflow instead of
using a heuristic that works only 99.9...% of the time.
Access *OFFSET only once, to avoid an unlikely race if the
compiler delays a load and if this cascades into a signed integer
overflow.
(mktime): Move tzsettish code to my_tzset, and move
localtime_offset to within mktime so that it doesn’t
need a separate ifdef.
(main) [DEBUG_MKTIME]: Speed up by using localtime_r
instead of localtime.
* time/timegm.c: Copy from Gnulib. This has the following changes:
Include mktime-internal.h.
[!_LIBC]: Include config.h and time.h. Do not include
timegm.h or time_r.h. Make __mktime_internal a macro,
and include mktime-internal.h to get its declaration.
(timegm): Temporary is now mktime_offset_t, not time_t.
This affects only Gnulib.
From the gnulib commit log:
commit e2646b0c6b5acda25e9ffeb4c12a5513a1e3b5ac
Author: Paul Eggert <eggert@cs.ucla.edu>
Date: Fri Jun 27 11:35:44 2014 -0700
mktime: merge #if/#ifdef usage from glibc
* lib/mktime.c: Use "#if defined DEBUG && DEBUG", not "#if DEBUG",
as that works with both Glibc's and Gnulib's style.
See thread starting at Siddhesh Poyarekar's bug report at:
http://lists.gnu.org/archive/html/bug-gnulib/2014-06/msg00102.html
* time/mktime.c (isdst_differ): New static function.
(__mktime_internal): No need to normalize tm_isdst now.
(__mktime_internal, not_equal_tm): Use isdst_differ to compare
tm_isdst values.
* time/mktime.c (TYPE_ONES_COMPLEMENT, TYPE_SIGNED_MAGNITUDE): Remove.
The code didn't really work on such machines anyway.
(TYPE_MINIMUM): Assume two's complement.
(twos_complement_arithmetic): Verify that long_int and time_t
are two's complement (or unsigned, in the latter case).
* time/mktime.c (verify): Move decl up.
(long_int): New type.
(leapyear, ydhms_diff, guess_time_tm, __mktime_internal): Use it,
to remove assumption in the code that 'long' is wide enough to
store year values. This assumption is not true on x32 and on
some non-glibc platforms.
* time/mktime.c (WRAPV): New macro.
(time_t_avg, time_t_add_ok, time_t_int_add_ok): New static functions.
(guess_time_tm, __mktime_internal): Do not assume that signed
integer overflow wraps around; modern compilers generate code
where this assumption is no longer valid.
2005-07-11 Derek R. Price <derek@ximbiot.com>
[BZ #1061]
* sysdeps/generic/glob.c (glob): Only a 0 return from
getlogin_r means success, according to POSIX 1003.2.
2005-06-23 Paul Eggert <eggert@cs.ucla.edu>
[BZ #1033]
* time/mktime.c: Import from gnulib.
The following macros are now consistent with other gnulib code.
This does not change mktime's behavior.
(TYPE_IS_INTEGER): New macro.
(time_t_is_integer): Use it.
(TYPE_TWOS_COMPLEMENT): New macro.
(twos_complement_arithmetic): Use it.
(TYPE_ONES_COMPLEMENT): New macro.
(TYPE_MINIMUM, TYPE_MAXIMUM): Now supports signed-magnitude.
mktime doesn't use this, but the code now matches other gnulib code.
(ranged_convert): Pacify GCC 4.0 in a different way, which
generates a few bytes less code.
(ranged_convert, __mktime_internal): When calling a function via a
pointer P, use P () rather than (*P) (), as we now assume C89 or
better.
implicitly used memcpy.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/truncate64.c
(truncate64): Use __truncate, not truncate.
(__have_no_truncate64): Renamed from have_no_truncate64.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/ftruncate64.c
(__have_no_truncate64): Renamed from have_no_truncate64.
2004-11-10 Paul Eggert <eggert@cs.ucla.edu>
[BZ #541]
* time/mktime.c (SHR): New macro, which is a portable
substitute for >> that should work even on Crays.
(TIME_T_MIDPOINT, ydhms_diff, __mktime_internal): Use it.
Problem reported by Mark D. Baushke in
<http://lists.gnu.org/archive/html/bug-gnulib/2004-11/msg00071.html>.
2004-10-27 Derek R. Price <derek@ximbiot.com>
[BZ #487] This change is imported from gnulib.
* time/mktime.c (not_equal_tm) [DEBUG]: Remove redundant check.
2004-10-24 Paul Eggert <eggert@cs.ucla.edu>
[BZ #473]
* time/tst-mktime.c (main): Don't assume that mktime fails
when given time stamps before 1970. It returns negative
time_t values instead, for compatibility with BSD.
* time/tst-mktime2.c: New file.
* time/Makefile (tests): Add it.
[BZ #473] Import from gnulib. Revamp to avoid several problems near
time_t extrema, and on hosts with 64-bit time_t and 32-bit int.
This fixes Debian bug 177940.
* time/mktime.c (TIME_T_MIDPOINT): New macro.
(ydhms_diff): Renamed from ydhms_tm_diff, with a new signature,
which avoids overflow problems on hosts with 64-bit time_t and
32-bit int. All callers changed. Now an inline function.
Verify at compile-time that long int is wide enough to avoid
these overflow problems.
(guess_time_tm): New function.
(__mktime_internal): Use it. Avoid overflow when computing yday on
hosts with 64-bit long and 32-bit int. Remove tests for 69;
no longer needed. Use if rather than #ifdef for LEAP_SECONDS_POSSIBLE
so that the code is checked by more compilers.
Do not rely on floating point to probe: stick to integer arithmetic,
to avoid potential porting problems.
Repair potential overflow correctly in the Southern Hemisphere.
(localtime_offset): Add a FIXME for the case where time_t is unsigned.
* time/mktime.c (leapyear, ydms_tm_diff): Year is of type
long int, not int, to avoid problems when tm_year == INT_MAX
and tm_mon > 12.
(__mktime_intenral): Compute year using long int arithmetic,
not int arithmetic, to avoid problems on hosts where time_t
and long are 64 bits but int is 32.
* time/mktime.c [!_LIBC] (__mktime_internal): Define to
mktime_internal, to avoid clashes with any __mktime_internal
function defined in the standard library.
* time/mktime.c (__isleap): Remove; all uses replaced by:
(leapyear): New function, which avoids overflow by not adding
1900 to year before testing whether it is a leap year.
* time/mktime.c (verify): New macro.
(time_t_is_integer, twos_complement_arithmetic,
right_shift_propagates_sign, base_year_is_a_multiple_of_100,
C99_integer_division): Document these longstanding assumptions in the
code, and verify them at compile-time.
Remove. All uses changed to __localtime_r.
(__localtime_r) [!defined _LIBC]: New macro. Include "time_r.h" to
get its implementation.
Fix compile-command to allow for TIME_R_POSIX.
* time/strftime.c (my_strftime_gmtime_r, my_strftime_localtime_r):
Remove. All uses changed to __localtime_r and __gmtime_r.
(__gmtime_r, __localtime_r) [!HAVE_TM_GMTOFF]: New macros.
Include "time_r.h" to get their implementations.
* time/timegm.c: Allow use in GNU applications outside glibc.
[defined HAVE_CONFIG_H]: Include <config.h>.
[!defined _LIBC]: Include "timegm.h", <time_r.h>.
Define __gmtime_r, and declare __mktime_internal.
(timegm): Define via a prototype, since we can safely assume C89 now.
* time/mktime.c (check_result): Use less-confusing report format.
"long" -> "long int", as per usual GNU style.
(main): Likewise.
Don't loop if the iteration overflows time_t.
Allow a negative step in the iteration.
* time/mktime.c: Assume freestanding C89 or better.
(HAVE_LIMITS_H, STDC_HEADERS) [defined _LIBC]: Remove;
assume they're 1.
(__P): Remove; not used.
(CHAR_BIT, INT_MIN, INT_MAX): Remove; <limits.h> defines them.
(mktime, not_equal_tm, print_tm, check_result, main): Use prototypes.
Prototypes use const * where appropriate.
(main) [DEBUG]: Fix typo in testing code uncovered by above changes,
which caused the testing code to dump core on some hosts.