parse-datetime: overflow and debug cleanups
commit30784c47105573c213cda1b3c4f397c8df837966
authorPaul Eggert <eggert@cs.ucla.edu>
Sat, 22 Apr 2017 09:11:26 +0000 (22 02:11 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 22 Apr 2017 09:13:15 +0000 (22 02:13 -0700)
tree196994f2bf794a1c0d7bcff1afddfe42841d1c2b
parent8fa38e3ebd5ee16c2166e14b55718aa5f28a0cd9
parse-datetime: overflow and debug cleanups

This long patch was triggered by this bug report from Ruediger Meier:
http://lists.gnu.org/archive/html/bug-gnulib/2017-04/msg00028.html
I fixed the bug he noted, then found some others nearby, and then
still others.  Oh my goodness, there were a lot of bugs.  I cleaned
up some of the code to follow GNU standards while I was at it.
* lib/parse-datetime.y (ISDIGIT): Remove; all callers changed to
use c_isdigit.
(EPOCH_YEAR): Remove; unused.
(TM_YEAR_BASE): Now an enum rather than a macro.
(HOUR, debug_strfdatetime): Multiply hour by 3600, not 60, to get
time zone offset, since timezones now are in terms of seconds and
not minutes.
(long_time_t): Remove.  All uses replaced by time_t or intmax_t as
appropriate.  Verify that intmax_t is wide enough.
(time_overflow, time_zone_str): New functions, used to deal
more reliably with overflow.
(dbg_printf): Add printf attribute, to help catch integer width errors.
(textint, relative_time, parser_control, time_zone_hhmm, set_hhmmss)
(%union, to_hour, yylex, parse_datetime2):
Use intmax_t instead of long int and/or long_time_t.
All uses changed.
(DBGBUFSIZE): Move earlier.
(relative_time, set_hhmmss, parser_control):
Just use int for nanoseconds and for time zones; that’s wide enough.
(parser_control): Use bool for members like year_seen that can
be booleans instead of counters.  All uses changed.
Remove debug_default_input_timezone; no longer needed.
All uses removed.
(apply_relative_time): Return a bool overflow flag.
All uses changed to check for overflow.
(apply_relative_time, zone, date, relunit, relunit_snumber)
(signed_seconds, unsigned_seconds, yylex, parse_datetime2):
Check for integer overflow portably.
(str_days): Use just int for N, as it’s wide enough.
Prefer 2D char arrays to arrays of char * when it looks like
2D is a win on typical platforms.
Prefer snprintf to strncpy/strncat, for simplicity;
all buffers are smaller than INT_MAX so this is safe.
(TIME_ZONE_BUFSiZE, TM_YEAR_BUFSIZE): New constants.
(debug_print_current_time): Don’t assume tv_nsec is of type long,
as this is not true on x32.  Output "." before any nanoseconds.
(debug_print_current_time, parse_datetime2):
Output local zones using a more-consistent format.
(debug_print_current_time, date, parse_datetime2):
(main) [TEST]:
Don’t assume time_t is the same width as long.
(print_rel_part): New function, replacing ...
(PRINT_REL_PART): ... this macro, which was removed.  All uses changed.
(debug_print_relative_time): Use bool for boolean.
(local_zone): dsts_seen now counts only tDST instances.
(date): Fix printf of size_t to use %z.  Do not assume numeric
tokens have negative values merely because the context suggests
a syntax with "-" separating tokens.
(time_zone_hhmm): Return bool success indicator, which checks for
overflow.  Store result into PC->time_zone instead.  All callers
changed.
(tm_year_str): New function.  Return a bool success indicator and
store the result into a buffer.  All callers changed.  Output the
numerically correct string even if adding 1900 to the year would
overflow.
(to_tm_year): New function, replacing the old to_year.  All
callers changed.
(tm_diff): Sync with glibc.
(lookup_word): Use to_uchar instead of doing it by hand.
(TZBUFSIZE): Now local to the only function that needs it.
(debug_strfdatetime): Simplify now that time zones are int seconds.
(debug_strfdate): Work even if tm_year + 1900 would overflow.
(get_effective_timezone): Remove.  All uses removed.
(parse_datetime2): Use fprintf in pieces instead of snprintfing
to a fixed-size buffer.  Don’t assume that gmtime succeeds iff
localtime succeeds.  Use tm_gmtoff if available.  Simplify how
‘goto fail;’ works in conjunction with the ‘ok’ flag.
* m4/parse-datetime.m4 (gl_PARSE_DATETIME): Don’t define
TIME_T_FITS_IN_LONG_INT, as it is no longer needed.
* modules/parse-datetime (Depends-on): Add inttypes.
ChangeLog
lib/parse-datetime.y
m4/parse-datetime.m4
modules/parse-datetime