Commit 4fd8d6b3 authored by Tom Lane's avatar Tom Lane

Fix crash caused by log_timezone patch if we attempt to emit any elog messages

between the setting of log_line_prefix and the setting of log_timezone.  We
can't realistically set log_timezone any earlier than we do now, so the best
behavior seems to be to use GMT zone if any timestamps are to be logged during
early startup.  Create a dummy zone variable with a minimal definition of GMT
(in particular it will never know about leap seconds), so that we can set it
up without reference to any external files.
parent 0b9d3d4d
......@@ -42,7 +42,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.192 2007/08/04 01:26:54 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.193 2007/08/04 19:29:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1497,16 +1497,25 @@ log_line_prefix(StringInfo buf)
{
struct timeval tv;
pg_time_t stamp_time;
pg_tz *tz;
char strfbuf[128],
msbuf[8];
gettimeofday(&tv, NULL);
stamp_time = (pg_time_t) tv.tv_sec;
/*
* Normally we print log timestamps in log_timezone, but
* during startup we could get here before that's set.
* If so, fall back to gmt_timezone (which guc.c ensures
* is set up before Log_line_prefix can become nonempty).
*/
tz = log_timezone ? log_timezone : gmt_timezone;
pg_strftime(strfbuf, sizeof(strfbuf),
/* leave room for milliseconds... */
"%Y-%m-%d %H:%M:%S %Z",
pg_localtime(&stamp_time, log_timezone));
pg_localtime(&stamp_time, tz));
/* 'paste' milliseconds into place... */
sprintf(msbuf, ".%03d", (int) (tv.tv_usec / 1000));
......@@ -1518,22 +1527,28 @@ log_line_prefix(StringInfo buf)
case 't':
{
pg_time_t stamp_time = (pg_time_t) time(NULL);
pg_tz *tz;
char strfbuf[128];
tz = log_timezone ? log_timezone : gmt_timezone;
pg_strftime(strfbuf, sizeof(strfbuf),
"%Y-%m-%d %H:%M:%S %Z",
pg_localtime(&stamp_time, log_timezone));
pg_localtime(&stamp_time, tz));
appendStringInfoString(buf, strfbuf);
}
break;
case 's':
{
pg_time_t stamp_time = (pg_time_t) MyStartTime;
pg_tz *tz;
char strfbuf[128];
tz = log_timezone ? log_timezone : gmt_timezone;
pg_strftime(strfbuf, sizeof(strfbuf),
"%Y-%m-%d %H:%M:%S %Z",
pg_localtime(&stamp_time, log_timezone));
pg_localtime(&stamp_time, tz));
appendStringInfoString(buf, strfbuf);
}
break;
......
......@@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.409 2007/08/04 01:26:54 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.410 2007/08/04 19:29:25 tgl Exp $
*
*--------------------------------------------------------------------
*/
......@@ -2926,6 +2926,12 @@ InitializeGUCOptions(void)
char *env;
long stack_rlimit;
/*
* Before log_line_prefix could possibly receive a nonempty setting,
* make sure that timezone processing is minimally alive (see elog.c).
*/
pg_timezone_pre_initialize();
/*
* Build sorted array of all GUC variables.
*/
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/include/pgtime.h,v 1.16 2007/08/04 01:26:54 tgl Exp $
* $PostgreSQL: pgsql/src/include/pgtime.h,v 1.17 2007/08/04 19:29:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -52,6 +52,7 @@ extern int pg_next_dst_boundary(const pg_time_t *timep,
extern size_t pg_strftime(char *s, size_t max, const char *format,
const struct pg_tm * tm);
extern void pg_timezone_pre_initialize(void);
extern void pg_timezone_initialize(void);
extern pg_tz *pg_tzset(const char *tzname);
extern bool tz_acceptable(pg_tz *tz);
......@@ -64,6 +65,7 @@ extern void pg_tzenumerate_end(pg_tzenum *dir);
extern pg_tz *session_timezone;
extern pg_tz *log_timezone;
extern pg_tz *gmt_timezone;
/* Maximum length of a timezone name (not including trailing null) */
#define TZ_STRLEN_MAX 255
......
......@@ -3,7 +3,7 @@
* 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/timezone/localtime.c,v 1.16 2006/10/18 16:43:14 tgl Exp $
* $PostgreSQL: pgsql/src/timezone/localtime.c,v 1.17 2007/08/04 19:29:25 tgl Exp $
*/
/*
......@@ -88,7 +88,6 @@ static void timesub(const pg_time_t *timep, long offset,
const struct state * sp, struct pg_tm * tmp);
static pg_time_t transtime(pg_time_t janfirst, int year,
const struct rule * rulep, long offset);
int tzparse(const char *name, struct state * sp, int lastditch);
/* GMT timezone */
static struct state gmtmem;
......@@ -549,6 +548,12 @@ tzparse(const char *name, struct state * sp, int lastditch)
if (stdlen >= sizeof sp->chars)
stdlen = (sizeof sp->chars) - 1;
stdoffset = 0;
/*
* Unlike the original zic library, do NOT invoke tzload() here;
* we can't assume pg_open_tzfile() is sane yet, and we don't
* care about leap seconds anyway.
*/
load_result = -1;
}
else
{
......@@ -561,8 +566,8 @@ tzparse(const char *name, struct state * sp, int lastditch)
name = getoffset(name, &stdoffset);
if (name == NULL)
return -1;
load_result = tzload(TZDEFRULES, NULL, sp);
}
load_result = tzload(TZDEFRULES, NULL, sp);
if (load_result != 0)
sp->leapcnt = 0; /* so, we're off a little */
if (*name != '\0')
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.52 2007/08/04 01:26:54 tgl Exp $
* $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.53 2007/08/04 19:29:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -33,6 +33,10 @@ pg_tz *session_timezone = NULL;
/* Current log timezone (controlled by log_timezone GUC) */
pg_tz *log_timezone = NULL;
/* Fallback GMT timezone for last-ditch error message formatting */
pg_tz *gmt_timezone = NULL;
static pg_tz gmt_timezone_data;
static char tzdir[MAXPGPATH];
static bool done_tzdir = false;
......@@ -1251,6 +1255,31 @@ select_default_timezone(void)
return NULL; /* keep compiler quiet */
}
/*
* Pre-initialize timezone library
*
* This is called before GUC variable initialization begins. Its purpose
* is to ensure that elog.c has a pgtz variable available to format timestamps
* with, in case log_line_prefix is set to a value requiring that. We cannot
* set log_timezone yet.
*/
void
pg_timezone_pre_initialize(void)
{
/*
* We can't use tzload() because we may not know where PGSHAREDIR
* is (in particular this is true in an EXEC_BACKEND subprocess).
* Since this timezone variable will only be used for emergency
* fallback purposes, it seems OK to just use the "lastditch" case
* provided by tzparse().
*/
if (tzparse("GMT", &gmt_timezone_data.state, TRUE) != 0)
elog(FATAL, "could not initialize GMT timezone");
strcpy(gmt_timezone_data.TZname, "GMT");
gmt_timezone = &gmt_timezone_data;
}
/*
* Initialize timezone library
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment