Skip to content

Commit 3f72158

Browse files
committed
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.
1 parent 9387f4e commit 3f72158

File tree

6 files changed

+36
-23
lines changed

6 files changed

+36
-23
lines changed

src/backend/bootstrap/bootstrap.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -199,14 +199,6 @@ AuxiliaryProcessMain(int argc, char *argv[])
199199

200200
MyStartTime = time(NULL);
201201

202-
/*
203-
* Fire up essential subsystems: error and memory management
204-
*
205-
* If we are running under the postmaster, this is done already.
206-
*/
207-
if (!IsUnderPostmaster)
208-
MemoryContextInit();
209-
210202
/* Compute paths, if we didn't inherit them from postmaster */
211203
if (my_exec_path[0] == '\0')
212204
{

src/backend/main/main.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "postmaster/postmaster.h"
4040
#include "tcop/tcopprot.h"
4141
#include "utils/help_config.h"
42+
#include "utils/memutils.h"
4243
#include "utils/pg_locale.h"
4344
#include "utils/ps_status.h"
4445
#ifdef WIN32
@@ -89,6 +90,15 @@ main(int argc, char *argv[])
8990
pgwin32_install_crashdump_handler();
9091
#endif
9192

93+
/*
94+
* Fire up essential subsystems: error and memory management
95+
*
96+
* Code after this point is allowed to use elog/ereport, though
97+
* localization of messages may not work right away, and messages won't go
98+
* anywhere but stderr until GUC settings get loaded.
99+
*/
100+
MemoryContextInit();
101+
92102
/*
93103
* Set up locale information from environment. Note that LC_CTYPE and
94104
* LC_COLLATE will be overridden later from pg_control if we are in an

src/backend/postmaster/postmaster.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -498,11 +498,6 @@ PostmasterMain(int argc, char *argv[])
498498
*/
499499
umask(S_IRWXG | S_IRWXO);
500500

501-
/*
502-
* Fire up essential subsystems: memory management
503-
*/
504-
MemoryContextInit();
505-
506501
/*
507502
* By default, palloc() requests in the postmaster will be allocated in
508503
* the PostmasterContext, which is space that can be recycled by backends.
@@ -3989,7 +3984,6 @@ SubPostmasterMain(int argc, char *argv[])
39893984
whereToSendOutput = DestNone;
39903985

39913986
/* Setup essential subsystems (to ensure elog() behaves sanely) */
3992-
MemoryContextInit();
39933987
InitializeGUCOptions();
39943988

39953989
/* Read in the variables file */

src/backend/tcop/postgres.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3531,14 +3531,6 @@ PostgresMain(int argc, char *argv[],
35313531
MyStartTime = time(NULL);
35323532
}
35333533

3534-
/*
3535-
* Fire up essential subsystems: error and memory management
3536-
*
3537-
* If we are running under the postmaster, this is done already.
3538-
*/
3539-
if (!IsUnderPostmaster)
3540-
MemoryContextInit();
3541-
35423534
SetProcessingMode(InitProcessing);
35433535

35443536
/* Compute paths, if we didn't inherit them from postmaster */

src/backend/utils/error/elog.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,18 @@ errstart(int elevel, const char *filename, int lineno,
301301
if (elevel < ERROR && !output_to_server && !output_to_client)
302302
return false;
303303

304+
/*
305+
* We need to do some actual work. Make sure that memory context
306+
* initialization has finished, else we can't do anything useful.
307+
*/
308+
if (ErrorContext == NULL)
309+
{
310+
/* Ooops, hard crash time; very little we can do safely here */
311+
write_stderr("error occurred at %s:%d before error message processing is available\n",
312+
filename ? filename : "(unknown file)", lineno);
313+
exit(2);
314+
}
315+
304316
/*
305317
* Okay, crank up a stack entry to store the info in.
306318
*/
@@ -1137,6 +1149,15 @@ elog_start(const char *filename, int lineno, const char *funcname)
11371149
{
11381150
ErrorData *edata;
11391151

1152+
/* Make sure that memory context initialization has finished */
1153+
if (ErrorContext == NULL)
1154+
{
1155+
/* Ooops, hard crash time; very little we can do safely here */
1156+
write_stderr("error occurred at %s:%d before error message processing is available\n",
1157+
filename ? filename : "(unknown file)", lineno);
1158+
exit(2);
1159+
}
1160+
11401161
if (++errordata_stack_depth >= ERRORDATA_STACK_SIZE)
11411162
{
11421163
/*

src/backend/utils/mmgr/mcxt.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ static void MemoryContextStatsInternal(MemoryContext context, int level);
6868
* In normal multi-backend operation, this is called once during
6969
* postmaster startup, and not at all by individual backend startup
7070
* (since the backends inherit an already-initialized context subsystem
71-
* by virtue of being forked off the postmaster).
71+
* by virtue of being forked off the postmaster). But in an EXEC_BACKEND
72+
* build, each process must do this for itself.
7273
*
7374
* In a standalone backend this must be called during backend startup.
7475
*/
@@ -102,6 +103,9 @@ MemoryContextInit(void)
102103
* where retained memory in a context is *essential* --- we want to be
103104
* sure ErrorContext still has some memory even if we've run out
104105
* elsewhere!
106+
*
107+
* This should be the last step in this function, as elog.c assumes memory
108+
* management works once ErrorContext is non-null.
105109
*/
106110
ErrorContext = AllocSetContextCreate(TopMemoryContext,
107111
"ErrorContext",

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy