On 02/25/2014 08:50 AM, Pádraig Brady wrote: > On 02/25/2014 08:13 AM, Mike Frysinger wrote: >> as reported by Bertrand Jacquin, this crashes: >> $ date -d 'TZ="America/Los_Angeles" "00:00 + 1 hour"' >> Segmentation fault >> >> (gdb) bt >> #0 0x00007ffff7ab1014 in __GI___libc_free (mem=0x7fffffffc8b0) at >> malloc.c:2942 >> #1 0x0000000000406730 in parse_datetime >> (result=result@entry=0x7fffffffcab0, p=<optimized out>, >> p@entry=0x7fffffffd04a "TZ=\"America/Los_Angeles\" \"00:00 + 1 hour\"", >> now=<optimized out>, now >> @entry=0x0) at ./lib/parse-datetime.y:1307 >> #2 0x00000000004023c7 in main (argc=0x3, argv=0x7fffffffcc68) at >> src/date.c:522 >> >> that's 15fca2a02e38d69915c52ef41eee3c7d52b67f3e i happened to have already >> built, but seems to reproduce easily across older versions. >> -mike >> > > Ugh. Reproducible here. > I'll fix up the issue in gnulib.
Proposed patch attached. thanks, Pádraig.
>From 6959d3a75b298a36c021e022216a27810948634f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1draig=20Brady?= <p...@draigbrady.com> Date: Tue, 25 Feb 2014 10:58:48 +0000 Subject: [PATCH] parse-datetime: fix crash or infloop in TZ="" parsing This was reported in http://bugs.gnu.org/16872 from the coreutils command: date -d 'TZ="""' The infinite loop for this case was present since the initial TZ="" parsing support in commit de95bdc2 29-10-2004. This was changed to a crash or heap corruption depending on the platform with commit 2e3e4195 18-01-2010. * lib/parse-datetime.y (parse_datetime): Break out of the TZ="" parsing loop once the second significant " is found. Also skip over any subsequent whitespace to be consistent with the non TZ= case. * tests/test-parse-datetime.c: Add test cases for TZ="" parsing. --- ChangeLog | 9 +++++++++ lib/parse-datetime.y | 7 +++++-- tests/test-parse-datetime.c | 16 ++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index fcb9afc..4f20fda 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2014-02-25 Pádraig Brady <p...@draigbrady.com> + + parse-datetime: fix crash or infloop in TZ="" parsing + * lib/parse-datetime.y (parse_datetime): Break out of the + TZ="" parsing loop once the second significant " is found. + Also skip over any subsequent whitespace to be consistent + with the non TZ= case. + * tests/test-parse-datetime.c: Add test cases for TZ="" parsing. + 2014-02-23 Paul Eggert <egg...@cs.ucla.edu> diffseq: remove TOO_EXPENSIVE heuristic diff --git a/lib/parse-datetime.y b/lib/parse-datetime.y index 6ece765..0ba0a52 100644 --- a/lib/parse-datetime.y +++ b/lib/parse-datetime.y @@ -1303,8 +1303,6 @@ parse_datetime (struct timespec *result, char const *p, char tz1buf[TZBUFSIZE]; bool large_tz = TZBUFSIZE < tzsize; bool setenv_ok; - /* Free tz0, in case this is the 2nd or subsequent time through. */ - free (tz0); tz0 = get_tz (tz0buf); z = tz1 = large_tz ? xmalloc (tzsize) : tz1buf; for (s = tzbase; *s != '"'; s++) @@ -1316,7 +1314,12 @@ parse_datetime (struct timespec *result, char const *p, if (!setenv_ok) goto fail; tz_was_altered = true; + p = s + 1; + while (c = *p, c_isspace (c)) + p++; + + break; } } diff --git a/tests/test-parse-datetime.c b/tests/test-parse-datetime.c index a410d3d..25385ca 100644 --- a/tests/test-parse-datetime.c +++ b/tests/test-parse-datetime.c @@ -419,5 +419,21 @@ main (int argc _GL_UNUSED, char **argv) starting with a high-bit-set byte would be treated like "0". */ ASSERT ( ! parse_datetime (&result, "\xb0", &now)); + /* Exercise TZ="" parsing code. */ + /* These two would infloop or segfault before Feb 2014. */ + ASSERT ( ! parse_datetime (&result, "TZ=\"\"\"", &now)); + ASSERT ( ! parse_datetime (&result, "TZ=\"\" \"", &now)); + /* Exercise invalid patterns. */ + ASSERT ( ! parse_datetime (&result, "TZ=\"", &now)); + ASSERT ( ! parse_datetime (&result, "TZ=\"\\\"", &now)); + ASSERT ( ! parse_datetime (&result, "TZ=\"\\n", &now)); + ASSERT ( ! parse_datetime (&result, "TZ=\"\\n\"", &now)); + /* Exercise valid patterns. */ + ASSERT ( parse_datetime (&result, "TZ=\"\"", &now)); + ASSERT ( parse_datetime (&result, "TZ=\"\" ", &now)); + ASSERT ( parse_datetime (&result, " TZ=\"\"", &now)); + ASSERT ( parse_datetime (&result, "TZ=\"\\\\\"", &now)); + ASSERT ( parse_datetime (&result, "TZ=\"\\\"\"", &now)); + return 0; } -- 1.7.7.6