Skip to content

Commit 7e25217

Browse files
committed
Don't leak malloc'd strings when a GUC setting is rejected.
Because guc.c prefers to keep all its string values in malloc'd not palloc'd storage, it has to be more careful than usual to avoid leaks. Error exits out of string GUC hook checks failed to clear the proposed value string, and error exits out of ProcessGUCArray() failed to clear the malloc'd results of ParseLongOption(). Found via valgrind testing. This problem is ancient, so back-patch to all supported branches. Discussion: https://postgr.es/m/3816764.1616104288@sss.pgh.pa.us
1 parent 09e9619 commit 7e25217

File tree

1 file changed

+47
-24
lines changed
  • src/backend/utils/misc

1 file changed

+47
-24
lines changed

src/backend/utils/misc/guc.c

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9412,6 +9412,8 @@ ProcessGUCArray(ArrayType *array,
94129412
char *s;
94139413
char *name;
94149414
char *value;
9415+
char *namecopy;
9416+
char *valuecopy;
94159417

94169418
d = array_ref(array, 1, &i,
94179419
-1 /* varlenarray */ ,
@@ -9436,13 +9438,18 @@ ProcessGUCArray(ArrayType *array,
94369438
continue;
94379439
}
94389440

9439-
(void) set_config_option(name, value,
9441+
/* free malloc'd strings immediately to avoid leak upon error */
9442+
namecopy = pstrdup(name);
9443+
free(name);
9444+
valuecopy = pstrdup(value);
9445+
free(value);
9446+
9447+
(void) set_config_option(namecopy, valuecopy,
94409448
context, source,
94419449
action, true, 0, false);
94429450

9443-
free(name);
9444-
if (value)
9445-
free(value);
9451+
pfree(namecopy);
9452+
pfree(valuecopy);
94469453
pfree(s);
94479454
}
94489455
}
@@ -9874,34 +9881,50 @@ static bool
98749881
call_string_check_hook(struct config_string * conf, char **newval, void **extra,
98759882
GucSource source, int elevel)
98769883
{
9884+
volatile bool result = true;
9885+
98779886
/* Quick success if no hook */
98789887
if (!conf->check_hook)
98799888
return true;
98809889

9881-
/* Reset variables that might be set by hook */
9882-
GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE;
9883-
GUC_check_errmsg_string = NULL;
9884-
GUC_check_errdetail_string = NULL;
9885-
GUC_check_errhint_string = NULL;
9890+
/*
9891+
* If elevel is ERROR, or if the check_hook itself throws an elog
9892+
* (undesirable, but not always avoidable), make sure we don't leak the
9893+
* already-malloc'd newval string.
9894+
*/
9895+
PG_TRY();
9896+
{
9897+
/* Reset variables that might be set by hook */
9898+
GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE;
9899+
GUC_check_errmsg_string = NULL;
9900+
GUC_check_errdetail_string = NULL;
9901+
GUC_check_errhint_string = NULL;
98869902

9887-
if (!(*conf->check_hook) (newval, extra, source))
9903+
if (!(*conf->check_hook) (newval, extra, source))
9904+
{
9905+
ereport(elevel,
9906+
(errcode(GUC_check_errcode_value),
9907+
GUC_check_errmsg_string ?
9908+
errmsg_internal("%s", GUC_check_errmsg_string) :
9909+
errmsg("invalid value for parameter \"%s\": \"%s\"",
9910+
conf->gen.name, *newval ? *newval : ""),
9911+
GUC_check_errdetail_string ?
9912+
errdetail_internal("%s", GUC_check_errdetail_string) : 0,
9913+
GUC_check_errhint_string ?
9914+
errhint("%s", GUC_check_errhint_string) : 0));
9915+
/* Flush any strings created in ErrorContext */
9916+
FlushErrorState();
9917+
result = false;
9918+
}
9919+
}
9920+
PG_CATCH();
98889921
{
9889-
ereport(elevel,
9890-
(errcode(GUC_check_errcode_value),
9891-
GUC_check_errmsg_string ?
9892-
errmsg_internal("%s", GUC_check_errmsg_string) :
9893-
errmsg("invalid value for parameter \"%s\": \"%s\"",
9894-
conf->gen.name, *newval ? *newval : ""),
9895-
GUC_check_errdetail_string ?
9896-
errdetail_internal("%s", GUC_check_errdetail_string) : 0,
9897-
GUC_check_errhint_string ?
9898-
errhint("%s", GUC_check_errhint_string) : 0));
9899-
/* Flush any strings created in ErrorContext */
9900-
FlushErrorState();
9901-
return false;
9922+
free(*newval);
9923+
PG_RE_THROW();
99029924
}
9925+
PG_END_TRY();
99039926

9904-
return true;
9927+
return result;
99059928
}
99069929

99079930
static bool

0 commit comments

Comments
 (0)