gdatetime: Avoid an assertion failure when parsing some ISO 8601 dates

Some malformed ISO 8601 date/time strings were causing an assertion
failure when passed to `g_date_time_new_from_iso8601()`, due to a
mismatch between the bounds checking of timezone offsets in `GDateTime`
and `GTimeZone`. Fix that and add a unit test for it.

oss-fuzz#16101

Signed-off-by: Philip Withnall <withnall@endlessm.com>
This commit is contained in:
Philip Withnall 2019-07-30 14:37:48 +01:00
parent 5558c668a9
commit 4ddabfc612
2 changed files with 11 additions and 6 deletions

View File

@ -1327,9 +1327,7 @@ static GTimeZone *
parse_iso8601_timezone (const gchar *text, gsize length, gssize *tz_offset) parse_iso8601_timezone (const gchar *text, gsize length, gssize *tz_offset)
{ {
gint i, tz_length, offset_hours, offset_minutes; gint i, tz_length, offset_hours, offset_minutes;
#ifndef G_DISABLE_ASSERT
gint offset_sign = 1; gint offset_sign = 1;
#endif
GTimeZone *tz; GTimeZone *tz;
/* UTC uses Z suffix */ /* UTC uses Z suffix */
@ -1343,9 +1341,7 @@ parse_iso8601_timezone (const gchar *text, gsize length, gssize *tz_offset)
for (i = length - 1; i >= 0; i--) for (i = length - 1; i >= 0; i--)
if (text[i] == '+' || text[i] == '-') if (text[i] == '+' || text[i] == '-')
{ {
#ifndef G_DISABLE_ASSERT
offset_sign = text[i] == '-' ? -1 : 1; offset_sign = text[i] == '-' ? -1 : 1;
#endif
break; break;
} }
if (i < 0) if (i < 0)
@ -1380,8 +1376,14 @@ parse_iso8601_timezone (const gchar *text, gsize length, gssize *tz_offset)
tz = g_time_zone_new (text + i); tz = g_time_zone_new (text + i);
/* Double-check that the GTimeZone matches our interpretation of the timezone. /* Double-check that the GTimeZone matches our interpretation of the timezone.
* Failure would indicate a bug either here of in the GTimeZone code. */ * This can fail because our interpretation is less strict than (for example)
g_assert (g_time_zone_get_offset (tz, 0) == offset_sign * (offset_hours * 3600 + offset_minutes * 60)); * parse_time() in gtimezone.c, which restricts the range of the parsed
* integers. */
if (g_time_zone_get_offset (tz, 0) != offset_sign * (offset_hours * 3600 + offset_minutes * 60))
{
g_time_zone_unref (tz);
return NULL;
}
return tz; return tz;
} }

View File

@ -499,6 +499,9 @@ test_GDateTime_new_from_iso8601 (void)
dt = g_date_time_new_from_iso8601 ("not a date", NULL); dt = g_date_time_new_from_iso8601 ("not a date", NULL);
g_assert_null (dt); g_assert_null (dt);
dt = g_date_time_new_from_iso8601 (" +55", NULL);
g_assert_null (dt);
/* Check common case */ /* Check common case */
dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42Z", NULL); dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42Z", NULL);
ASSERT_DATE (dt, 2016, 8, 24); ASSERT_DATE (dt, 2016, 8, 24);