Skip to content

Commit a5c77e6

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 9f3d3fb commit a5c77e6

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
@@ -6202,6 +6202,10 @@ set_config_option(const char *name, const char *value,
62026202

62036203
if (prohibitValueChange)
62046204
{
6205+
/* Release newextra, unless it's reset_extra */
6206+
if (newextra && !extra_field_used(&conf->gen, newextra))
6207+
free(newextra);
6208+
62056209
if (*conf->variable != newval)
62066210
{
62076211
record->status |= GUC_PENDING_RESTART;
@@ -6292,6 +6296,10 @@ set_config_option(const char *name, const char *value,
62926296

62936297
if (prohibitValueChange)
62946298
{
6299+
/* Release newextra, unless it's reset_extra */
6300+
if (newextra && !extra_field_used(&conf->gen, newextra))
6301+
free(newextra);
6302+
62956303
if (*conf->variable != newval)
62966304
{
62976305
record->status |= GUC_PENDING_RESTART;
@@ -6382,6 +6390,10 @@ set_config_option(const char *name, const char *value,
63826390

63836391
if (prohibitValueChange)
63846392
{
6393+
/* Release newextra, unless it's reset_extra */
6394+
if (newextra && !extra_field_used(&conf->gen, newextra))
6395+
free(newextra);
6396+
63856397
if (*conf->variable != newval)
63866398
{
63876399
record->status |= GUC_PENDING_RESTART;
@@ -6488,9 +6500,21 @@ set_config_option(const char *name, const char *value,
64886500

64896501
if (prohibitValueChange)
64906502
{
6503+
bool newval_different;
6504+
64916505
/* newval shouldn't be NULL, so we're a bit sloppy here */
6492-
if (*conf->variable == NULL || newval == NULL ||
6493-
strcmp(*conf->variable, newval) != 0)
6506+
newval_different = (*conf->variable == NULL ||
6507+
newval == NULL ||
6508+
strcmp(*conf->variable, newval) != 0);
6509+
6510+
/* Release newval, unless it's reset_val */
6511+
if (newval && !string_field_used(conf, newval))
6512+
free(newval);
6513+
/* Release newextra, unless it's reset_extra */
6514+
if (newextra && !extra_field_used(&conf->gen, newextra))
6515+
free(newextra);
6516+
6517+
if (newval_different)
64946518
{
64956519
record->status |= GUC_PENDING_RESTART;
64966520
ereport(elevel,
@@ -6585,6 +6609,10 @@ set_config_option(const char *name, const char *value,
65856609

65866610
if (prohibitValueChange)
65876611
{
6612+
/* Release newextra, unless it's reset_extra */
6613+
if (newextra && !extra_field_used(&conf->gen, newextra))
6614+
free(newextra);
6615+
65886616
if (*conf->variable != newval)
65896617
{
65906618
record->status |= GUC_PENDING_RESTART;

0 commit comments

Comments
 (0)