Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 7e25217

Browse filesBrowse 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
Copy full SHA for 7e25217

File tree

Expand file treeCollapse file tree

1 file changed

+47
-24
lines changed
Filter options
  • src/backend/utils/misc
Expand file treeCollapse file tree

1 file changed

+47
-24
lines changed

‎src/backend/utils/misc/guc.c

Copy file name to clipboardExpand all lines: src/backend/utils/misc/guc.c
+47-24Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.