Skip to content

Commit f0c2a5b

Browse files
committed
Avoid leaking memory in RestoreGUCState(), and improve comments.
RestoreGUCState applied InitializeOneGUCOption to already-live GUC entries, causing any malloc'd subsidiary data to be forgotten. We do want the effect of resetting the GUC to its compiled-in default, and InitializeOneGUCOption seems like the best way to do that, so add code to free any existing subsidiary data beforehand. The interaction between can_skip_gucvar, SerializeGUCState, and RestoreGUCState is way more subtle than their opaque comments would suggest to an unwary reader. Rewrite and enlarge the comments to try to make it clearer what's happening. Remove a long-obsolete assertion in read_nondefault_variables: the behavior of set_config_option hasn't depended on IsInitProcessingMode since f5d9698 installed a better way of controlling it. Although this is fixing a clear memory leak, the leak is quite unlikely to involve any large amount of data, and it can only happen once in the lifetime of a worker process. So it seems unnecessary to take any risk of back-patching. Discussion: https://postgr.es/m/4105247.1616174862@sss.pgh.pa.us
1 parent 61752af commit f0c2a5b

File tree

1 file changed

+140
-30
lines changed
  • src/backend/utils/misc

1 file changed

+140
-30
lines changed

src/backend/utils/misc/guc.c

Lines changed: 140 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7121,6 +7121,10 @@ parse_and_validate_value(struct config_generic *record,
71217121
* its standard choice of ereport level. However some callers need to be
71227122
* able to override that choice; they should pass the ereport level to use.
71237123
*
7124+
* is_reload should be true only when called from read_nondefault_variables()
7125+
* or RestoreGUCState(), where we are trying to load some other process's
7126+
* GUC settings into a new process.
7127+
*
71247128
* Return value:
71257129
* +1: the value is valid and was successfully applied.
71267130
* 0: the name or value is invalid (but see below).
@@ -10258,12 +10262,6 @@ read_nondefault_variables(void)
1025810262
GucSource varsource;
1025910263
GucContext varscontext;
1026010264

10261-
/*
10262-
* Assert that PGC_BACKEND/PGC_SU_BACKEND case in set_config_option() will
10263-
* do the right thing.
10264-
*/
10265-
Assert(IsInitProcessingMode());
10266-
1026710265
/*
1026810266
* Open file
1026910267
*/
@@ -10317,30 +10315,43 @@ read_nondefault_variables(void)
1031710315

1031810316
/*
1031910317
* can_skip_gucvar:
10320-
* When serializing, determine whether to skip this GUC. When restoring, the
10321-
* negation of this test determines whether to restore the compiled-in default
10322-
* value before processing serialized values.
10318+
* Decide whether SerializeGUCState can skip sending this GUC variable,
10319+
* or whether RestoreGUCState can skip resetting this GUC to default.
1032310320
*
10324-
* A PGC_S_DEFAULT setting on the serialize side will typically match new
10325-
* postmaster children, but that can be false when got_SIGHUP == true and the
10326-
* pending configuration change modifies this setting. Nonetheless, we omit
10327-
* PGC_S_DEFAULT settings from serialization and make up for that by restoring
10328-
* defaults before applying serialized values.
10329-
*
10330-
* PGC_POSTMASTER variables always have the same value in every child of a
10331-
* particular postmaster. Most PGC_INTERNAL variables are compile-time
10332-
* constants; a few, like server_encoding and lc_ctype, are handled specially
10333-
* outside the serialize/restore procedure. Therefore, SerializeGUCState()
10334-
* never sends these, and RestoreGUCState() never changes them.
10335-
*
10336-
* Role is a special variable in the sense that its current value can be an
10337-
* invalid value and there are multiple ways by which that can happen (like
10338-
* after setting the role, someone drops it). So we handle it outside of
10339-
* serialize/restore machinery.
10321+
* It is somewhat magical and fragile that the same test works for both cases.
10322+
* Realize in particular that we are very likely selecting different sets of
10323+
* GUCs on the leader and worker sides! Be sure you've understood the
10324+
* comments here and in RestoreGUCState thoroughly before changing this.
1034010325
*/
1034110326
static bool
1034210327
can_skip_gucvar(struct config_generic *gconf)
1034310328
{
10329+
/*
10330+
* We can skip GUCs that are guaranteed to have the same values in leaders
10331+
* and workers. (Note it is critical that the leader and worker have the
10332+
* same idea of which GUCs fall into this category. It's okay to consider
10333+
* context and name for this purpose, since those are unchanging
10334+
* properties of a GUC.)
10335+
*
10336+
* PGC_POSTMASTER variables always have the same value in every child of a
10337+
* particular postmaster, so the worker will certainly have the right
10338+
* value already. Likewise, PGC_INTERNAL variables are set by special
10339+
* mechanisms (if indeed they aren't compile-time constants). So we may
10340+
* always skip these.
10341+
*
10342+
* Role must be handled specially because its current value can be an
10343+
* invalid value (for instance, if someone dropped the role since we set
10344+
* it). So if we tried to serialize it normally, we might get a failure.
10345+
* We skip it here, and use another mechanism to ensure the worker has the
10346+
* right value.
10347+
*
10348+
* For all other GUCs, we skip if the GUC has its compiled-in default
10349+
* value (i.e., source == PGC_S_DEFAULT). On the leader side, this means
10350+
* we don't send GUCs that have their default values, which typically
10351+
* saves lots of work. On the worker side, this means we don't need to
10352+
* reset the GUC to default because it already has that value. See
10353+
* comments in RestoreGUCState for more info.
10354+
*/
1034410355
return gconf->context == PGC_POSTMASTER ||
1034510356
gconf->context == PGC_INTERNAL || gconf->source == PGC_S_DEFAULT ||
1034610357
strcmp(gconf->name, "role") == 0;
@@ -10358,6 +10369,7 @@ estimate_variable_size(struct config_generic *gconf)
1035810369
Size size;
1035910370
Size valsize = 0;
1036010371

10372+
/* Skippable GUCs consume zero space. */
1036110373
if (can_skip_gucvar(gconf))
1036210374
return 0;
1036310375

@@ -10522,6 +10534,7 @@ static void
1052210534
serialize_variable(char **destptr, Size *maxbytes,
1052310535
struct config_generic *gconf)
1052410536
{
10537+
/* Ignore skippable GUCs. */
1052510538
if (can_skip_gucvar(gconf))
1052610539
return;
1052710540

@@ -10669,8 +10682,14 @@ guc_restore_error_context_callback(void *arg)
1066910682

1067010683
/*
1067110684
* RestoreGUCState:
10672-
* Reads the GUC state at the specified address and updates the GUCs with the
10673-
* values read from the GUC state.
10685+
* Reads the GUC state at the specified address and sets this process's
10686+
* GUCs to match.
10687+
*
10688+
* Note that this provides the worker with only a very shallow view of the
10689+
* leader's GUC state: we'll know about the currently active values, but not
10690+
* about stacked or reset values. That's fine since the worker is just
10691+
* executing one part of a query, within which the active values won't change
10692+
* and the stacked values are invisible.
1067410693
*/
1067510694
void
1067610695
RestoreGUCState(void *gucstate)
@@ -10687,10 +10706,100 @@ RestoreGUCState(void *gucstate)
1068710706
int i;
1068810707
ErrorContextCallback error_context_callback;
1068910708

10690-
/* See comment at can_skip_gucvar(). */
10709+
/*
10710+
* First, ensure that all potentially-shippable GUCs are reset to their
10711+
* default values. We must not touch those GUCs that the leader will
10712+
* never ship, while there is no need to touch those that are shippable
10713+
* but already have their default values. Thus, this ends up being the
10714+
* same test that SerializeGUCState uses, even though the sets of
10715+
* variables involved may well be different since the leader's set of
10716+
* variables-not-at-default-values can differ from the set that are
10717+
* not-default in this freshly started worker.
10718+
*
10719+
* Once we have set all the potentially-shippable GUCs to default values,
10720+
* restoring the GUCs that the leader sent (because they had non-default
10721+
* values over there) leads us to exactly the set of GUC values that the
10722+
* leader has. This is true even though the worker may have initially
10723+
* absorbed postgresql.conf settings that the leader hasn't yet seen, or
10724+
* ALTER USER/DATABASE SET settings that were established after the leader
10725+
* started.
10726+
*
10727+
* Note that ensuring all the potential target GUCs are at PGC_S_DEFAULT
10728+
* also ensures that set_config_option won't refuse to set them because of
10729+
* source-priority comparisons.
10730+
*/
1069110731
for (i = 0; i < num_guc_variables; i++)
10692-
if (!can_skip_gucvar(guc_variables[i]))
10693-
InitializeOneGUCOption(guc_variables[i]);
10732+
{
10733+
struct config_generic *gconf = guc_variables[i];
10734+
10735+
/* Do nothing if non-shippable or if already at PGC_S_DEFAULT. */
10736+
if (can_skip_gucvar(gconf))
10737+
continue;
10738+
10739+
/*
10740+
* We can use InitializeOneGUCOption to reset the GUC to default, but
10741+
* first we must free any existing subsidiary data to avoid leaking
10742+
* memory. The stack must be empty, but we have to clean up all other
10743+
* fields. Beware that there might be duplicate value or "extra"
10744+
* pointers.
10745+
*/
10746+
Assert(gconf->stack == NULL);
10747+
if (gconf->extra)
10748+
free(gconf->extra);
10749+
if (gconf->last_reported) /* probably can't happen */
10750+
free(gconf->last_reported);
10751+
if (gconf->sourcefile)
10752+
free(gconf->sourcefile);
10753+
switch (gconf->vartype)
10754+
{
10755+
case PGC_BOOL:
10756+
{
10757+
struct config_bool *conf = (struct config_bool *) gconf;
10758+
10759+
if (conf->reset_extra && conf->reset_extra != gconf->extra)
10760+
free(conf->reset_extra);
10761+
break;
10762+
}
10763+
case PGC_INT:
10764+
{
10765+
struct config_int *conf = (struct config_int *) gconf;
10766+
10767+
if (conf->reset_extra && conf->reset_extra != gconf->extra)
10768+
free(conf->reset_extra);
10769+
break;
10770+
}
10771+
case PGC_REAL:
10772+
{
10773+
struct config_real *conf = (struct config_real *) gconf;
10774+
10775+
if (conf->reset_extra && conf->reset_extra != gconf->extra)
10776+
free(conf->reset_extra);
10777+
break;
10778+
}
10779+
case PGC_STRING:
10780+
{
10781+
struct config_string *conf = (struct config_string *) gconf;
10782+
10783+
if (*conf->variable)
10784+
free(*conf->variable);
10785+
if (conf->reset_val && conf->reset_val != *conf->variable)
10786+
free(conf->reset_val);
10787+
if (conf->reset_extra && conf->reset_extra != gconf->extra)
10788+
free(conf->reset_extra);
10789+
break;
10790+
}
10791+
case PGC_ENUM:
10792+
{
10793+
struct config_enum *conf = (struct config_enum *) gconf;
10794+
10795+
if (conf->reset_extra && conf->reset_extra != gconf->extra)
10796+
free(conf->reset_extra);
10797+
break;
10798+
}
10799+
}
10800+
/* Now we can reset the struct to PGS_S_DEFAULT state. */
10801+
InitializeOneGUCOption(gconf);
10802+
}
1069410803

1069510804
/* First item is the length of the subsequent data */
1069610805
memcpy(&len, gucstate, sizeof(len));
@@ -10704,6 +10813,7 @@ RestoreGUCState(void *gucstate)
1070410813
error_context_callback.arg = NULL;
1070510814
error_context_stack = &error_context_callback;
1070610815

10816+
/* Restore all the listed GUCs. */
1070710817
while (srcptr < srcend)
1070810818
{
1070910819
int result;

0 commit comments

Comments
 (0)