mirror of
https://github.com/postgres/postgres.git
synced 2025-07-20 05:03:10 +03:00
Reject out-of-range numeric timezone specifications.
In commit 631dc390f4
, we started to handle
simple numeric timezone offsets via the zic library instead of the old
CTimeZone/HasCTZSet kluge. However, we overlooked the fact that the zic
code will reject UTC offsets exceeding a week (which seems a bit arbitrary,
but not because it's too tight ...). This led to possibly setting
session_timezone to NULL, which results in crashes in most timezone-related
operations as of 9.4, and crashes in a small number of places even before
that. So check for NULL return from pg_tzset_offset() and report an
appropriate error message. Per bug #11014 from Duncan Gillis.
Back-patch to all supported branches, like the previous patch.
(Unfortunately, as of today that no longer includes 8.4.)
This commit is contained in:
@ -241,6 +241,8 @@ assign_timezone(const char *value, bool doit, GucSource source)
|
|||||||
char *result;
|
char *result;
|
||||||
char *endptr;
|
char *endptr;
|
||||||
double hours;
|
double hours;
|
||||||
|
int new_ctimezone;
|
||||||
|
pg_tz *new_tz;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for INTERVAL 'foo'
|
* Check for INTERVAL 'foo'
|
||||||
@ -294,16 +296,28 @@ assign_timezone(const char *value, bool doit, GucSource source)
|
|||||||
pfree(interval);
|
pfree(interval);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Here we change from SQL to Unix sign convention */
|
||||||
|
#ifdef HAVE_INT64_TIMESTAMP
|
||||||
|
new_ctimezone = -(interval->time / USECS_PER_SEC);
|
||||||
|
#else
|
||||||
|
new_ctimezone = -interval->time;
|
||||||
|
#endif
|
||||||
|
new_tz = pg_tzset_offset(new_ctimezone);
|
||||||
|
|
||||||
|
if (!new_tz)
|
||||||
|
{
|
||||||
|
ereport(GUC_complaint_elevel(source),
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("invalid interval value for time zone: out of range")));
|
||||||
|
pfree(interval);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (doit)
|
if (doit)
|
||||||
{
|
{
|
||||||
/* Here we change from SQL to Unix sign convention */
|
CTimeZone = new_ctimezone;
|
||||||
#ifdef HAVE_INT64_TIMESTAMP
|
session_timezone = new_tz;
|
||||||
CTimeZone = -(interval->time / USECS_PER_SEC);
|
|
||||||
#else
|
|
||||||
CTimeZone = -interval->time;
|
|
||||||
#endif
|
|
||||||
session_timezone = pg_tzset_offset(CTimeZone);
|
|
||||||
|
|
||||||
HasCTZSet = true;
|
HasCTZSet = true;
|
||||||
}
|
}
|
||||||
pfree(interval);
|
pfree(interval);
|
||||||
@ -316,11 +330,22 @@ assign_timezone(const char *value, bool doit, GucSource source)
|
|||||||
hours = strtod(value, &endptr);
|
hours = strtod(value, &endptr);
|
||||||
if (endptr != value && *endptr == '\0')
|
if (endptr != value && *endptr == '\0')
|
||||||
{
|
{
|
||||||
|
/* Here we change from SQL to Unix sign convention */
|
||||||
|
new_ctimezone = -hours * SECS_PER_HOUR;
|
||||||
|
new_tz = pg_tzset_offset(new_ctimezone);
|
||||||
|
|
||||||
|
if (!new_tz)
|
||||||
|
{
|
||||||
|
ereport(GUC_complaint_elevel(source),
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("invalid value for time zone: out of range")));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (doit)
|
if (doit)
|
||||||
{
|
{
|
||||||
/* Here we change from SQL to Unix sign convention */
|
CTimeZone = new_ctimezone;
|
||||||
CTimeZone = -hours * SECS_PER_HOUR;
|
session_timezone = new_tz;
|
||||||
session_timezone = pg_tzset_offset(CTimeZone);
|
|
||||||
HasCTZSet = true;
|
HasCTZSet = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -352,8 +377,6 @@ assign_timezone(const char *value, bool doit, GucSource source)
|
|||||||
/*
|
/*
|
||||||
* Otherwise assume it is a timezone name, and try to load it.
|
* Otherwise assume it is a timezone name, and try to load it.
|
||||||
*/
|
*/
|
||||||
pg_tz *new_tz;
|
|
||||||
|
|
||||||
new_tz = pg_tzset(value);
|
new_tz = pg_tzset(value);
|
||||||
|
|
||||||
if (!new_tz)
|
if (!new_tz)
|
||||||
|
@ -1333,6 +1333,9 @@ pg_tzset(const char *name)
|
|||||||
* The GMT offset is specified in seconds, positive values meaning west of
|
* The GMT offset is specified in seconds, positive values meaning west of
|
||||||
* Greenwich (ie, POSIX not ISO sign convention). However, we use ISO
|
* Greenwich (ie, POSIX not ISO sign convention). However, we use ISO
|
||||||
* sign convention in the displayable abbreviation for the zone.
|
* sign convention in the displayable abbreviation for the zone.
|
||||||
|
*
|
||||||
|
* Caution: this can fail (return NULL) if the specified offset is outside
|
||||||
|
* the range allowed by the zic library.
|
||||||
*/
|
*/
|
||||||
pg_tz *
|
pg_tz *
|
||||||
pg_tzset_offset(long gmtoffset)
|
pg_tzset_offset(long gmtoffset)
|
||||||
|
Reference in New Issue
Block a user