Re: Report a potential memory leak in setup_config() - Mailing list pgsql-bugs
| From | Tom Lane |
|---|---|
| Subject | Re: Report a potential memory leak in setup_config() |
| Date | |
| Msg-id | 3255493.1644985807@sss.pgh.pa.us Whole thread Raw |
| In response to | Re: Report a potential memory leak in setup_config() (Andres Freund <andres@anarazel.de>) |
| Responses |
Re: Report a potential memory leak in setup_config()
Re: Report a potential memory leak in setup_config() |
| List | pgsql-bugs |
Andres Freund <andres@anarazel.de> writes:
> When I'd looked at this last I apparently (looking at git stash, I ended up
> discarding this) decided that the best way would be to change replace_token's
> API to one that just processes one line at a time, with an outer loop that
> processes all tokens in a line. I'm not really sure why anymore.
Hmm, I did it the other way, as attached. This gets it down to
==3254266== LEAK SUMMARY:
==3254266== definitely lost: 342 bytes in 17 blocks
==3254266== indirectly lost: 152 bytes in 2 blocks
==3254266== possibly lost: 0 bytes in 0 blocks
==3254266== still reachable: 2,403 bytes in 22 blocks
==3254266== suppressed: 0 bytes in 0 blocks
It seems that actually the pointer arrays *are* a big chunk of
the leakage, because the individual strings get freed in the
output loops! That's a bit ugly but I feel no need to change it.
regards, tom lane
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 97f15971e2..76cb3a142e 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -237,11 +237,11 @@ static const char *const subdirs[] = {
static char bin_path[MAXPGPATH];
static char backend_exec[MAXPGPATH];
-static char **replace_token(char **lines,
+static void replace_token(char **lines,
const char *token, const char *replacement);
#ifndef HAVE_UNIX_SOCKETS
-static char **filter_lines_with_token(char **lines, const char *token);
+static void remove_lines_with_token(char **lines, const char *token);
#endif
static char **readfile(const char *path);
static void writefile(char *path, char **lines);
@@ -363,43 +363,33 @@ escape_quotes_bki(const char *src)
}
/*
- * make a copy of the array of lines, with token replaced by replacement
+ * Modify an array of malloc'd strings, replacing token by replacement
* the first time it occurs on each line.
*
* This does most of what sed was used for in the shell script, but
* doesn't need any regexp stuff.
*/
-static char **
+static void
replace_token(char **lines, const char *token, const char *replacement)
{
- int numlines = 1;
int i;
- char **result;
int toklen,
replen,
diff;
- for (i = 0; lines[i]; i++)
- numlines++;
-
- result = (char **) pg_malloc(numlines * sizeof(char *));
-
toklen = strlen(token);
replen = strlen(replacement);
diff = replen - toklen;
- for (i = 0; i < numlines; i++)
+ for (i = 0; lines[i]; i++)
{
char *where;
char *newline;
int pre;
- /* just copy pointer if NULL or no change needed */
- if (lines[i] == NULL || (where = strstr(lines[i], token)) == NULL)
- {
- result[i] = lines[i];
+ /* no work if no change needed */
+ if ((where = strstr(lines[i], token)) == NULL)
continue;
- }
/* if we get here a change is needed - set up new line */
@@ -413,39 +403,31 @@ replace_token(char **lines, const char *token, const char *replacement)
strcpy(newline + pre + replen, lines[i] + pre + toklen);
- result[i] = newline;
+ free(lines[i]);
+ lines[i] = newline;
}
-
- return result;
}
/*
- * make a copy of lines without any that contain the token
+ * remove strings from lines[] if they contain the token
*
* a sort of poor man's grep -v
*/
#ifndef HAVE_UNIX_SOCKETS
-static char **
-filter_lines_with_token(char **lines, const char *token)
+static void
+remove_lines_with_token(char **lines, const char *token)
{
- int numlines = 1;
- int i,
- src,
+ int src,
dst;
- char **result;
-
- for (i = 0; lines[i]; i++)
- numlines++;
-
- result = (char **) pg_malloc(numlines * sizeof(char *));
- for (src = 0, dst = 0; src < numlines; src++)
+ for (src = 0, dst = 0; lines[src]; src++)
{
- if (lines[src] == NULL || strstr(lines[src], token) == NULL)
- result[dst++] = lines[src];
+ if (strstr(lines[src], token) == NULL)
+ lines[dst++] = lines[src];
+ else
+ free(lines[src]);
}
-
- return result;
+ lines[dst] = NULL;
}
#endif
@@ -1066,7 +1048,7 @@ setup_config(void)
conflines = readfile(conf_file);
snprintf(repltok, sizeof(repltok), "max_connections = %d", n_connections);
- conflines = replace_token(conflines, "#max_connections = 100", repltok);
+ replace_token(conflines, "#max_connections = 100", repltok);
if ((n_buffers * (BLCKSZ / 1024)) % 1024 == 0)
snprintf(repltok, sizeof(repltok), "shared_buffers = %dMB",
@@ -1074,7 +1056,7 @@ setup_config(void)
else
snprintf(repltok, sizeof(repltok), "shared_buffers = %dkB",
n_buffers * (BLCKSZ / 1024));
- conflines = replace_token(conflines, "#shared_buffers = 128MB", repltok);
+ replace_token(conflines, "#shared_buffers = 128MB", repltok);
#ifdef HAVE_UNIX_SOCKETS
snprintf(repltok, sizeof(repltok), "#unix_socket_directories = '%s'",
@@ -1082,38 +1064,38 @@ setup_config(void)
#else
snprintf(repltok, sizeof(repltok), "#unix_socket_directories = ''");
#endif
- conflines = replace_token(conflines, "#unix_socket_directories = '/tmp'",
+ replace_token(conflines, "#unix_socket_directories = '/tmp'",
repltok);
#if DEF_PGPORT != 5432
snprintf(repltok, sizeof(repltok), "#port = %d", DEF_PGPORT);
- conflines = replace_token(conflines, "#port = 5432", repltok);
+ replace_token(conflines, "#port = 5432", repltok);
#endif
/* set default max_wal_size and min_wal_size */
snprintf(repltok, sizeof(repltok), "min_wal_size = %s",
pretty_wal_size(DEFAULT_MIN_WAL_SEGS));
- conflines = replace_token(conflines, "#min_wal_size = 80MB", repltok);
+ replace_token(conflines, "#min_wal_size = 80MB", repltok);
snprintf(repltok, sizeof(repltok), "max_wal_size = %s",
pretty_wal_size(DEFAULT_MAX_WAL_SEGS));
- conflines = replace_token(conflines, "#max_wal_size = 1GB", repltok);
+ replace_token(conflines, "#max_wal_size = 1GB", repltok);
snprintf(repltok, sizeof(repltok), "lc_messages = '%s'",
escape_quotes(lc_messages));
- conflines = replace_token(conflines, "#lc_messages = 'C'", repltok);
+ replace_token(conflines, "#lc_messages = 'C'", repltok);
snprintf(repltok, sizeof(repltok), "lc_monetary = '%s'",
escape_quotes(lc_monetary));
- conflines = replace_token(conflines, "#lc_monetary = 'C'", repltok);
+ replace_token(conflines, "#lc_monetary = 'C'", repltok);
snprintf(repltok, sizeof(repltok), "lc_numeric = '%s'",
escape_quotes(lc_numeric));
- conflines = replace_token(conflines, "#lc_numeric = 'C'", repltok);
+ replace_token(conflines, "#lc_numeric = 'C'", repltok);
snprintf(repltok, sizeof(repltok), "lc_time = '%s'",
escape_quotes(lc_time));
- conflines = replace_token(conflines, "#lc_time = 'C'", repltok);
+ replace_token(conflines, "#lc_time = 'C'", repltok);
switch (locale_date_order(lc_time))
{
@@ -1128,12 +1110,12 @@ setup_config(void)
strcpy(repltok, "datestyle = 'iso, mdy'");
break;
}
- conflines = replace_token(conflines, "#datestyle = 'iso, mdy'", repltok);
+ replace_token(conflines, "#datestyle = 'iso, mdy'", repltok);
snprintf(repltok, sizeof(repltok),
"default_text_search_config = 'pg_catalog.%s'",
escape_quotes(default_text_search_config));
- conflines = replace_token(conflines,
+ replace_token(conflines,
"#default_text_search_config = 'pg_catalog.simple'",
repltok);
@@ -1141,46 +1123,46 @@ setup_config(void)
{
snprintf(repltok, sizeof(repltok), "timezone = '%s'",
escape_quotes(default_timezone));
- conflines = replace_token(conflines, "#timezone = 'GMT'", repltok);
+ replace_token(conflines, "#timezone = 'GMT'", repltok);
snprintf(repltok, sizeof(repltok), "log_timezone = '%s'",
escape_quotes(default_timezone));
- conflines = replace_token(conflines, "#log_timezone = 'GMT'", repltok);
+ replace_token(conflines, "#log_timezone = 'GMT'", repltok);
}
snprintf(repltok, sizeof(repltok), "dynamic_shared_memory_type = %s",
dynamic_shared_memory_type);
- conflines = replace_token(conflines, "#dynamic_shared_memory_type = posix",
+ replace_token(conflines, "#dynamic_shared_memory_type = posix",
repltok);
#if DEFAULT_BACKEND_FLUSH_AFTER > 0
snprintf(repltok, sizeof(repltok), "#backend_flush_after = %dkB",
DEFAULT_BACKEND_FLUSH_AFTER * (BLCKSZ / 1024));
- conflines = replace_token(conflines, "#backend_flush_after = 0",
+ replace_token(conflines, "#backend_flush_after = 0",
repltok);
#endif
#if DEFAULT_BGWRITER_FLUSH_AFTER > 0
snprintf(repltok, sizeof(repltok), "#bgwriter_flush_after = %dkB",
DEFAULT_BGWRITER_FLUSH_AFTER * (BLCKSZ / 1024));
- conflines = replace_token(conflines, "#bgwriter_flush_after = 0",
+ replace_token(conflines, "#bgwriter_flush_after = 0",
repltok);
#endif
#if DEFAULT_CHECKPOINT_FLUSH_AFTER > 0
snprintf(repltok, sizeof(repltok), "#checkpoint_flush_after = %dkB",
DEFAULT_CHECKPOINT_FLUSH_AFTER * (BLCKSZ / 1024));
- conflines = replace_token(conflines, "#checkpoint_flush_after = 0",
+ replace_token(conflines, "#checkpoint_flush_after = 0",
repltok);
#endif
#ifndef USE_PREFETCH
- conflines = replace_token(conflines,
+ replace_token(conflines,
"#effective_io_concurrency = 1",
"#effective_io_concurrency = 0");
#endif
#ifdef WIN32
- conflines = replace_token(conflines,
+ replace_token(conflines,
"#update_process_title = on",
"#update_process_title = off");
#endif
@@ -1194,7 +1176,7 @@ setup_config(void)
(strcmp(authmethodhost, "md5") == 0 &&
strcmp(authmethodlocal, "scram-sha-256") != 0))
{
- conflines = replace_token(conflines,
+ replace_token(conflines,
"#password_encryption = scram-sha-256",
"password_encryption = md5");
}
@@ -1207,7 +1189,7 @@ setup_config(void)
*/
if (pg_dir_create_mode == PG_DIR_MODE_GROUP)
{
- conflines = replace_token(conflines,
+ replace_token(conflines,
"#log_file_mode = 0600",
"log_file_mode = 0640");
}
@@ -1248,9 +1230,9 @@ setup_config(void)
conflines = readfile(hba_file);
#ifndef HAVE_UNIX_SOCKETS
- conflines = filter_lines_with_token(conflines, "@remove-line-for-nolocal@");
+ remove_lines_with_token(conflines, "@remove-line-for-nolocal@");
#else
- conflines = replace_token(conflines, "@remove-line-for-nolocal@", "");
+ replace_token(conflines, "@remove-line-for-nolocal@", "");
#endif
#ifdef HAVE_IPV6
@@ -1287,33 +1269,33 @@ setup_config(void)
if (err != 0 ||
getaddrinfo("::1", NULL, &hints, &gai_result) != 0)
{
- conflines = replace_token(conflines,
+ replace_token(conflines,
"host all all ::1",
"#host all all ::1");
- conflines = replace_token(conflines,
+ replace_token(conflines,
"host replication all ::1",
"#host replication all ::1");
}
}
#else /* !HAVE_IPV6 */
/* If we didn't compile IPV6 support at all, always comment it out */
- conflines = replace_token(conflines,
+ replace_token(conflines,
"host all all ::1",
"#host all all ::1");
- conflines = replace_token(conflines,
+ replace_token(conflines,
"host replication all ::1",
"#host replication all ::1");
#endif /* HAVE_IPV6 */
/* Replace default authentication methods */
- conflines = replace_token(conflines,
+ replace_token(conflines,
"@authmethodhost@",
authmethodhost);
- conflines = replace_token(conflines,
+ replace_token(conflines,
"@authmethodlocal@",
authmethodlocal);
- conflines = replace_token(conflines,
+ replace_token(conflines,
"@authcomment@",
(strcmp(authmethodlocal, "trust") == 0 || strcmp(authmethodhost, "trust") == 0) ?
AUTHTRUST_WARNING: "");
@@ -1382,27 +1364,27 @@ bootstrap_template1(void)
/* Substitute for various symbols used in the BKI file */
sprintf(buf, "%d", NAMEDATALEN);
- bki_lines = replace_token(bki_lines, "NAMEDATALEN", buf);
+ replace_token(bki_lines, "NAMEDATALEN", buf);
sprintf(buf, "%d", (int) sizeof(Pointer));
- bki_lines = replace_token(bki_lines, "SIZEOF_POINTER", buf);
+ replace_token(bki_lines, "SIZEOF_POINTER", buf);
- bki_lines = replace_token(bki_lines, "ALIGNOF_POINTER",
+ replace_token(bki_lines, "ALIGNOF_POINTER",
(sizeof(Pointer) == 4) ? "i" : "d");
- bki_lines = replace_token(bki_lines, "FLOAT8PASSBYVAL",
+ replace_token(bki_lines, "FLOAT8PASSBYVAL",
FLOAT8PASSBYVAL ? "true" : "false");
- bki_lines = replace_token(bki_lines, "POSTGRES",
+ replace_token(bki_lines, "POSTGRES",
escape_quotes_bki(username));
- bki_lines = replace_token(bki_lines, "ENCODING",
+ replace_token(bki_lines, "ENCODING",
encodingid_to_string(encodingid));
- bki_lines = replace_token(bki_lines, "LC_COLLATE",
+ replace_token(bki_lines, "LC_COLLATE",
escape_quotes_bki(lc_collate));
- bki_lines = replace_token(bki_lines, "LC_CTYPE",
+ replace_token(bki_lines, "LC_CTYPE",
escape_quotes_bki(lc_ctype));
/* Also ensure backend isn't confused by this environment var: */
@@ -1624,7 +1606,8 @@ setup_privileges(FILE *cmdfd)
{
char **line;
char **priv_lines;
- static char *privileges_setup[] = {
+ int i;
+ static const char * const privileges_setup[] = {
"UPDATE pg_class "
" SET relacl = (SELECT array_agg(a.acl) FROM "
" (SELECT E'=r/\"$POSTGRES_SUPERUSERNAME\"' as acl "
@@ -1759,10 +1742,19 @@ setup_privileges(FILE *cmdfd)
NULL
};
- priv_lines = replace_token(privileges_setup, "$POSTGRES_SUPERUSERNAME",
+ priv_lines = (char**) pg_malloc(lengthof(privileges_setup) * sizeof(char*));
+ for (i = 0; privileges_setup[i]; i++)
+ priv_lines[i] = pg_strdup(privileges_setup[i]);
+ priv_lines[i] = NULL;
+
+ replace_token(priv_lines, "$POSTGRES_SUPERUSERNAME",
escape_quotes(username));
for (line = priv_lines; *line != NULL; line++)
+ {
PG_CMD_PUTS(*line);
+ free(*line);
+ }
+ free(priv_lines);
}
/*
pgsql-bugs by date: