psql: Fix memory leak with repeated calls of \bind

Calling \bind repeatedly would cause the memory allocated for the list
of bind parameters to be leaked after each call, as the list is reset
when beginning a single call.

This issue is fixed by making the cleanup of the bind parameter list
more aggressive, refactoring it into a single routine called after
processing a query and before running an individual \bind.

HEAD required more surgery and has been fixed by 87eeadaea143.  Issue
introduced by 5b66de3433e2.

Reported-by: Anthonin Bonnefoy
Discussion: https://postgr.es/m/2e5b89af-a351-ff0a-000c-037ac28314ab@gmail.com
Backpatch-through: 16
This commit is contained in:
Michael Paquier 2024-09-19 16:25:11 +09:00
parent 00c8c4180a
commit c2fb2f9e20
3 changed files with 23 additions and 9 deletions

View File

@ -470,7 +470,7 @@ exec_command_bind(PsqlScanState scan_state, bool active_branch)
int nparams = 0; int nparams = 0;
int nalloc = 0; int nalloc = 0;
pset.bind_params = NULL; clean_bind_state();
while ((opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false))) while ((opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false)))
{ {

View File

@ -1241,14 +1241,7 @@ sendquery_cleanup:
} }
/* clean up after \bind */ /* clean up after \bind */
if (pset.bind_flag) clean_bind_state();
{
for (i = 0; i < pset.bind_nparams; i++)
free(pset.bind_params[i]);
free(pset.bind_params);
pset.bind_params = NULL;
pset.bind_flag = false;
}
/* reset \gset trigger */ /* reset \gset trigger */
if (pset.gset_prefix) if (pset.gset_prefix)
@ -2413,6 +2406,26 @@ uri_prefix_length(const char *connstr)
return 0; return 0;
} }
/*
* Reset state related to \bind
*
* Clean up any state related to bind parameters and bind_flag. This needs
* to be called after processing a query or when running \bind.
*/
void
clean_bind_state(void)
{
if (pset.bind_flag)
{
for (int i = 0; i < pset.bind_nparams; i++)
free(pset.bind_params[i]);
free(pset.bind_params);
}
pset.bind_params = NULL;
pset.bind_flag = false;
}
/* /*
* Recognized connection string either starts with a valid URI prefix or * Recognized connection string either starts with a valid URI prefix or
* contains a "=" in it. * contains a "=" in it.

View File

@ -41,6 +41,7 @@ extern bool standard_strings(void);
extern const char *session_username(void); extern const char *session_username(void);
extern void expand_tilde(char **filename); extern void expand_tilde(char **filename);
extern void clean_bind_state(void);
extern bool recognized_connection_string(const char *connstr); extern bool recognized_connection_string(const char *connstr);