Skip to content

Commit 397ea90

Browse files
committed
Fix memory leak when guc.c decides a setting can't be applied now.
The prohibitValueChange code paths in set_config_option(), which are executed whenever we re-read a PGC_POSTMASTER variable from postgresql.conf, neglected to free anything before exiting. Thus we'd leak the proposed new value of a PGC_STRING variable, as noted by BoChen in bug #16666. For all variable types, if the check hook creates an "extra" chunk, we'd also leak that. These are malloc not palloc chunks, so there is no mechanism for recovering the leaks before process exit. Fortunately, the values are typically not very large, meaning you'd have to go through an awful lot of SIGHUP configuration-reload cycles to make the leakage amount to anything. Still, for a long-lived postmaster process it could potentially be a problem. Oversight in commit 2594cf0. Back-patch to all supported branches. Discussion: https://postgr.es/m/16666-2c41a4eec61b03e1@postgresql.org
1 parent fcd1132 commit 397ea90

File tree

1 file changed

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

1 file changed

+30
-2
lines changed

src/backend/utils/misc/guc.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7222,6 +7222,10 @@ set_config_option(const char *name, const char *value,
72227222

72237223
if (prohibitValueChange)
72247224
{
7225+
/* Release newextra, unless it's reset_extra */
7226+
if (newextra && !extra_field_used(&conf->gen, newextra))
7227+
free(newextra);
7228+
72257229
if (*conf->variable != newval)
72267230
{
72277231
record->status |= GUC_PENDING_RESTART;
@@ -7312,6 +7316,10 @@ set_config_option(const char *name, const char *value,
73127316

73137317
if (prohibitValueChange)
73147318
{
7319+
/* Release newextra, unless it's reset_extra */
7320+
if (newextra && !extra_field_used(&conf->gen, newextra))
7321+
free(newextra);
7322+
73157323
if (*conf->variable != newval)
73167324
{
73177325
record->status |= GUC_PENDING_RESTART;
@@ -7402,6 +7410,10 @@ set_config_option(const char *name, const char *value,
74027410

74037411
if (prohibitValueChange)
74047412
{
7413+
/* Release newextra, unless it's reset_extra */
7414+
if (newextra && !extra_field_used(&conf->gen, newextra))
7415+
free(newextra);
7416+
74057417
if (*conf->variable != newval)
74067418
{
74077419
record->status |= GUC_PENDING_RESTART;
@@ -7508,9 +7520,21 @@ set_config_option(const char *name, const char *value,
75087520

75097521
if (prohibitValueChange)
75107522
{
7523+
bool newval_different;
7524+
75117525
/* newval shouldn't be NULL, so we're a bit sloppy here */
7512-
if (*conf->variable == NULL || newval == NULL ||
7513-
strcmp(*conf->variable, newval) != 0)
7526+
newval_different = (*conf->variable == NULL ||
7527+
newval == NULL ||
7528+
strcmp(*conf->variable, newval) != 0);
7529+
7530+
/* Release newval, unless it's reset_val */
7531+
if (newval && !string_field_used(conf, newval))
7532+
free(newval);
7533+
/* Release newextra, unless it's reset_extra */
7534+
if (newextra && !extra_field_used(&conf->gen, newextra))
7535+
free(newextra);
7536+
7537+
if (newval_different)
75147538
{
75157539
record->status |= GUC_PENDING_RESTART;
75167540
ereport(elevel,
@@ -7605,6 +7629,10 @@ set_config_option(const char *name, const char *value,
76057629

76067630
if (prohibitValueChange)
76077631
{
7632+
/* Release newextra, unless it's reset_extra */
7633+
if (newextra && !extra_field_used(&conf->gen, newextra))
7634+
free(newextra);
7635+
76087636
if (*conf->variable != newval)
76097637
{
76107638
record->status |= GUC_PENDING_RESTART;

0 commit comments

Comments
 (0)