summaryrefslogtreecommitdiff
path: root/src/backend/utils
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2014-01-11 16:35:44 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2014-01-11 16:35:44 -0500
commitd0070ac81b46e8c77b158268a5a772fd1a993f05 (patch)
treec0df1806d64ea92cc2a266796b192c68c809fe5f /src/backend/utils
parent00b77771aa61c688fbca41fdb4657381b3a2fc90 (diff)
downloadpostgresql-d0070ac81b46e8c77b158268a5a772fd1a993f05.tar.gz
Fix possible crashes due to using elog/ereport too early in startup.
Per reports from Andres Freund and Luke Campbell, a server failure during set_pglocale_pgservice results in a segfault rather than a useful error message, because the infrastructure needed to use ereport hasn't been initialized; specifically, MemoryContextInit hasn't been called. One known cause of this is starting the server in a directory it doesn't have permission to read. We could try to prevent set_pglocale_pgservice from using anything that depends on palloc or elog, but that would be messy, and the odds of future breakage seem high. Moreover there are other things being called in main.c that look likely to use palloc or elog too --- perhaps those things shouldn't be there, but they are there today. The best solution seems to be to move the call of MemoryContextInit to very early in the backend's real main() function. I've verified that an elog or ereport occurring immediately after that is now capable of sending something useful to stderr. I also added code to elog.c to print something intelligible rather than just crashing if MemoryContextInit hasn't created the ErrorContext. This could happen if MemoryContextInit itself fails (due to malloc failure), and provides some future-proofing against someone trying to sneak in new code even earlier in server startup. Back-patch to all supported branches. Since we've only heard reports of this type of failure recently, it may be that some recent change has made it more likely to see a crash of this kind; but it sure looks like it's broken all the way back.
Diffstat (limited to 'src/backend/utils')
-rw-r--r--src/backend/utils/error/elog.c21
-rw-r--r--src/backend/utils/mmgr/mcxt.c6
2 files changed, 26 insertions, 1 deletions
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 6c4146a21c..99f2d81c0b 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -291,6 +291,18 @@ errstart(int elevel, const char *filename, int lineno,
return false;
/*
+ * We need to do some actual work. Make sure that memory context
+ * initialization has finished, else we can't do anything useful.
+ */
+ if (ErrorContext == NULL)
+ {
+ /* Ooops, hard crash time; very little we can do safely here */
+ write_stderr("error occurred at %s:%d before error message processing is available\n",
+ filename ? filename : "(unknown file)", lineno);
+ exit(2);
+ }
+
+ /*
* Okay, crank up a stack entry to store the info in.
*/
@@ -1095,6 +1107,15 @@ elog_start(const char *filename, int lineno, const char *funcname)
{
ErrorData *edata;
+ /* Make sure that memory context initialization has finished */
+ if (ErrorContext == NULL)
+ {
+ /* Ooops, hard crash time; very little we can do safely here */
+ write_stderr("error occurred at %s:%d before error message processing is available\n",
+ filename ? filename : "(unknown file)", lineno);
+ exit(2);
+ }
+
if (++errordata_stack_depth >= ERRORDATA_STACK_SIZE)
{
/*
diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c
index 9b08df366d..3430fd29cd 100644
--- a/src/backend/utils/mmgr/mcxt.c
+++ b/src/backend/utils/mmgr/mcxt.c
@@ -68,7 +68,8 @@ static void MemoryContextStatsInternal(MemoryContext context, int level);
* In normal multi-backend operation, this is called once during
* postmaster startup, and not at all by individual backend startup
* (since the backends inherit an already-initialized context subsystem
- * by virtue of being forked off the postmaster).
+ * by virtue of being forked off the postmaster). But in an EXEC_BACKEND
+ * build, each process must do this for itself.
*
* In a standalone backend this must be called during backend startup.
*/
@@ -102,6 +103,9 @@ MemoryContextInit(void)
* where retained memory in a context is *essential* --- we want to be
* sure ErrorContext still has some memory even if we've run out
* elsewhere!
+ *
+ * This should be the last step in this function, as elog.c assumes memory
+ * management works once ErrorContext is non-null.
*/
ErrorContext = AllocSetContextCreate(TopMemoryContext,
"ErrorContext",