mirror of
https://git.savannah.gnu.org/git/gnulib.git
synced 2025-08-08 17:22:05 +03:00
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.
This commit is contained in:
79
ChangeLog
79
ChangeLog
@@ -1,3 +1,82 @@
|
|||||||
|
2017-04-22 Paul Eggert <eggert@cs.ucla.edu>
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
2017-04-21 Bruno Haible <bruno@clisp.org>
|
2017-04-21 Bruno Haible <bruno@clisp.org>
|
||||||
|
|
||||||
gettext-h: Avoid -Wundef warning.
|
gettext-h: Avoid -Wundef warning.
|
||||||
|
1307
lib/parse-datetime.y
1307
lib/parse-datetime.y
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
# parse-datetime.m4 serial 21
|
# parse-datetime.m4 serial 22
|
||||||
dnl Copyright (C) 2002-2006, 2008-2017 Free Software Foundation, Inc.
|
dnl Copyright (C) 2002-2006, 2008-2017 Free Software Foundation, Inc.
|
||||||
dnl This file is free software; the Free Software Foundation
|
dnl This file is free software; the Free Software Foundation
|
||||||
dnl gives unlimited permission to copy and/or distribute it,
|
dnl gives unlimited permission to copy and/or distribute it,
|
||||||
@@ -36,20 +36,4 @@ AC_DEFUN([gl_PARSE_DATETIME],
|
|||||||
AC_STRUCT_TIMEZONE
|
AC_STRUCT_TIMEZONE
|
||||||
AC_REQUIRE([gl_CLOCK_TIME])
|
AC_REQUIRE([gl_CLOCK_TIME])
|
||||||
AC_REQUIRE([gl_TM_GMTOFF])
|
AC_REQUIRE([gl_TM_GMTOFF])
|
||||||
AC_COMPILE_IFELSE(
|
|
||||||
[AC_LANG_SOURCE([[
|
|
||||||
#include <time.h> /* for time_t */
|
|
||||||
#include <limits.h> /* for CHAR_BIT, LONG_MIN, LONG_MAX */
|
|
||||||
#define TYPE_MINIMUM(t) \
|
|
||||||
((t) ((t) 0 < (t) -1 ? (t) 0 : ~ TYPE_MAXIMUM (t)))
|
|
||||||
#define TYPE_MAXIMUM(t) \
|
|
||||||
((t) ((t) 0 < (t) -1 \
|
|
||||||
? (t) -1 \
|
|
||||||
: ((((t) 1 << (sizeof (t) * CHAR_BIT - 2)) - 1) * 2 + 1)))
|
|
||||||
typedef int verify_min[2 * (LONG_MIN <= TYPE_MINIMUM (time_t)) - 1];
|
|
||||||
typedef int verify_max[2 * (TYPE_MAXIMUM (time_t) <= LONG_MAX) - 1];
|
|
||||||
]])],
|
|
||||||
[AC_DEFINE([TIME_T_FITS_IN_LONG_INT], [1],
|
|
||||||
[Define to 1 if all 'time_t' values fit in a 'long int'.])
|
|
||||||
])
|
|
||||||
])
|
])
|
||||||
|
@@ -15,6 +15,7 @@ stdbool
|
|||||||
gettime
|
gettime
|
||||||
gettext-h
|
gettext-h
|
||||||
intprops
|
intprops
|
||||||
|
inttypes
|
||||||
mktime
|
mktime
|
||||||
setenv
|
setenv
|
||||||
strftime
|
strftime
|
||||||
|
Reference in New Issue
Block a user