From 1c284d1a4155136ddaee44eab7fd5d55a75962fc Mon Sep 17 00:00:00 2001 From: =?utf-8?q?Ond=C5=99ej=20Va=C5=A1=C3=ADk?= Date: Fri, 4 Jul 2008 17:44:57 +0200 Subject: [PATCH] getdate.y: add limits for TZ, handle TZ +HH format correctly * lib/getdate.y (time_zone_hh_mm): Allow only TZ in the range UTC-24 to UTC+24 hours, consider first two digits of TZ as hours when no minutes are specified and number is in the range -14 and +14 (as common TZ ranges UTC-12 to UTC+14). Invalid TZ will cause invalid date format error. * tests/test-getdate.c: Tests for that change --- ChangeLog | 9 ++++++++ lib/getdate.y | 35 ++++++++++++++++++++++++++------- tests/test-getdate.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6c5f522..076d70e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2008-07-04 Ondřej Vašík + + getdate.y: Allow only timezone range specified by POSIX + * lib/getdate.y (time_zone_hhmm): Allow only TZ in the range + -24 to +24 hours, consider first two digits between -14 and 14 + as hours (as common TZ ranges UTC-12 to UTC+14). Invalid TZ + will cause invalid format error. + * tests/test-getdate.c: Tests for the fix + 2008-07-04 Jim Meyering * users.txt: Add vc-dwim. diff --git a/lib/getdate.y b/lib/getdate.y index 695fd59..ace35be 100644 --- a/lib/getdate.y +++ b/lib/getdate.y @@ -205,7 +205,7 @@ typedef struct union YYSTYPE; static int yylex (union YYSTYPE *, parser_control *); static int yyerror (parser_control const *, char const *); -static long int time_zone_hhmm (textint, long int); +static long int time_zone_hhmm (parser_control *, textint, long int); /* Extract into *PC any date and time info from a string of digits of the form e.g., YYYYMMDD, YYMMDD, HHMM, HH (and sometimes YYY, @@ -358,7 +358,7 @@ time: set_hhmmss (pc, $1.value, $3.value, 0, 0); pc->meridian = MER24; pc->zones_seen++; - pc->time_zone = time_zone_hhmm ($4, $5); + pc->time_zone = time_zone_hhmm (pc, $4, $5); } | tUNUMBER ':' tUNUMBER ':' unsigned_seconds o_merid { @@ -370,7 +370,7 @@ time: set_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec); pc->meridian = MER24; pc->zones_seen++; - pc->time_zone = time_zone_hhmm ($6, $7); + pc->time_zone = time_zone_hhmm (pc, $6, $7); } ; @@ -394,7 +394,7 @@ zone: { pc->time_zone = $1; apply_relative_time (pc, $2, 1); } | tZONE tSNUMBER o_colon_minutes - { pc->time_zone = $1 + time_zone_hhmm ($2, $3); } + { pc->time_zone = $1 + time_zone_hhmm (pc, $2, $3); } | tDAYZONE { pc->time_zone = $1 + 60; } | tZONE tDST @@ -795,15 +795,34 @@ static table const military_table[] = /* Convert a time zone expressed as HH:MM into an integer count of minutes. If MM is negative, then S is of the form HHMM and needs - to be picked apart; otherwise, S is of the form HH. */ + to be picked apart; otherwise, S is of the form HH. As specified at + http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html + allow only valid TZ range, otherwise increment pc->zones_seen to cause + invalid format error. */ static long int -time_zone_hhmm (textint s, long int mm) +time_zone_hhmm (parser_control *pc, textint s, long int mm) { + long int returnvalue; + + /* if s.value is lower than 15, add 00 minutes if minutes are + not specified as common time zones ranges between UTC-1200 + and UTC+1400 */ + if ((abs (s.value) < 15) && (mm < 0)) + s.value *= 100; + if (mm < 0) - return (s.value / 100) * 60 + s.value % 100; + returnvalue = (s.value / 100) * 60 + s.value % 100; else - return s.value * 60 + (s.negative ? -mm : mm); + returnvalue = s.value * 60 + (s.negative ? -mm : mm); + + /* check if the return value is in real timezone range, + otherwise increment pc->zones_seen to cause time format + error, allow UTC-24:00 to UTC+24:00 */ + if (abs (returnvalue) > 1440) + pc->zones_seen++; + + return returnvalue; } static int diff --git a/tests/test-getdate.c b/tests/test-getdate.c index 901adf9..d84db84 100644 --- a/tests/test-getdate.c +++ b/tests/test-getdate.c @@ -53,6 +53,7 @@ main (int argc, char **argv) struct timespec result; struct timespec result2; struct timespec now; + int i; const char *p; now.tv_sec = 4711; @@ -98,5 +99,55 @@ main (int argc, char **argv) ASSERT (result.tv_sec == result2.tv_sec && result.tv_nsec == result2.tv_nsec); + /* test if several time zones formats are handled same way */ + now.tv_sec = 4711; + now.tv_nsec = 1267; + p = "UTC+14:00"; + ASSERT (get_date (&result, p, &now)); + LOG (p, now, result); + p = "UTC+14"; + ASSERT (get_date (&result2, p, &now)); + LOG (p, now, result2); + ASSERT (result.tv_sec == result2.tv_sec + && result.tv_nsec == result2.tv_nsec); + p = "UTC+1400"; + ASSERT (get_date (&result2, p, &now)); + LOG (p, now, result2); + ASSERT (result.tv_sec == result2.tv_sec + && result.tv_nsec == result2.tv_nsec); + + now.tv_sec = 4711; + now.tv_nsec = 1267; + p = "UTC-14:00"; + ASSERT (get_date (&result, p, &now)); + LOG (p, now, result); + p = "UTC-14"; + ASSERT (get_date (&result2, p, &now)); + LOG (p, now, result2); + ASSERT (result.tv_sec == result2.tv_sec + && result.tv_nsec == result2.tv_nsec); + p = "UTC-1400"; + ASSERT (get_date (&result2, p, &now)); + LOG (p, now, result2); + ASSERT (result.tv_sec == result2.tv_sec + && result.tv_nsec == result2.tv_nsec); + + now.tv_sec = 4711; + now.tv_nsec = 1267; + p = "UTC+00:15"; + ASSERT (get_date (&result, p, &now)); + LOG (p, now, result); + p = "UTC+15"; + ASSERT (get_date (&result2, p, &now)); + LOG (p, now, result2); + ASSERT (result.tv_sec == result2.tv_sec + && result.tv_nsec == result2.tv_nsec); + + /* TZ out of range should cause get_date failure */ + now.tv_sec = 4711; + now.tv_nsec = 1267; + p = "UTC+25:00"; + ASSERT (!get_date (&result, p, &now)); + return 0; } -- 1.5.6.1.156.ge903b