aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/bootstrap/bootstrap.c4
-rw-r--r--src/backend/commands/tablespace.c4
-rw-r--r--src/backend/commands/variable.c34
-rw-r--r--src/backend/postmaster/postmaster.c4
-rw-r--r--src/backend/replication/syncrep.c4
-rw-r--r--src/backend/tcop/postgres.c4
-rw-r--r--src/backend/utils/adt/datetime.c7
-rw-r--r--src/backend/utils/cache/ts_cache.c6
-rw-r--r--src/backend/utils/misc/README15
-rw-r--r--src/backend/utils/misc/guc.c225
-rw-r--r--src/backend/utils/misc/tzparser.c2
-rw-r--r--src/include/utils/guc.h1
-rw-r--r--src/pl/plpgsql/src/pl_handler.c2
13 files changed, 185 insertions, 127 deletions
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 22635f80947..58247d826dc 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -287,8 +287,8 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
}
SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
- free(name);
- free(value);
+ pfree(name);
+ pfree(value);
break;
}
default:
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index b69ff37dbbd..45b30ca566d 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -1290,8 +1290,8 @@ check_temp_tablespaces(char **newval, void **extra, GucSource source)
}
/* Now prepare an "extra" struct for assign_temp_tablespaces */
- myextra = malloc(offsetof(temp_tablespaces_extra, tblSpcs) +
- numSpcs * sizeof(Oid));
+ myextra = guc_malloc(LOG, offsetof(temp_tablespaces_extra, tblSpcs) +
+ numSpcs * sizeof(Oid));
if (!myextra)
return false;
myextra->numSpcs = numSpcs;
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index e555fb31501..791bac6715c 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -148,7 +148,7 @@ check_datestyle(char **newval, void **extra, GucSource source)
char *subval;
void *subextra = NULL;
- subval = strdup(GetConfigOptionResetString("datestyle"));
+ subval = guc_strdup(LOG, GetConfigOptionResetString("datestyle"));
if (!subval)
{
ok = false;
@@ -156,7 +156,7 @@ check_datestyle(char **newval, void **extra, GucSource source)
}
if (!check_datestyle(&subval, &subextra, source))
{
- free(subval);
+ guc_free(subval);
ok = false;
break;
}
@@ -165,8 +165,8 @@ check_datestyle(char **newval, void **extra, GucSource source)
newDateStyle = myextra[0];
if (!have_order)
newDateOrder = myextra[1];
- free(subval);
- free(subextra);
+ guc_free(subval);
+ guc_free(subextra);
}
else
{
@@ -187,9 +187,9 @@ check_datestyle(char **newval, void **extra, GucSource source)
}
/*
- * Prepare the canonical string to return. GUC wants it malloc'd.
+ * Prepare the canonical string to return. GUC wants it guc_malloc'd.
*/
- result = (char *) malloc(32);
+ result = (char *) guc_malloc(LOG, 32);
if (!result)
return false;
@@ -221,13 +221,13 @@ check_datestyle(char **newval, void **extra, GucSource source)
break;
}
- free(*newval);
+ guc_free(*newval);
*newval = result;
/*
* Set up the "extra" struct actually used by assign_datestyle.
*/
- myextra = (int *) malloc(2 * sizeof(int));
+ myextra = (int *) guc_malloc(LOG, 2 * sizeof(int));
if (!myextra)
return false;
myextra[0] = newDateStyle;
@@ -366,7 +366,7 @@ check_timezone(char **newval, void **extra, GucSource source)
/*
* Pass back data for assign_timezone to use
*/
- *extra = malloc(sizeof(pg_tz *));
+ *extra = guc_malloc(LOG, sizeof(pg_tz *));
if (!*extra)
return false;
*((pg_tz **) *extra) = new_tz;
@@ -439,7 +439,7 @@ check_log_timezone(char **newval, void **extra, GucSource source)
/*
* Pass back data for assign_log_timezone to use
*/
- *extra = malloc(sizeof(pg_tz *));
+ *extra = guc_malloc(LOG, sizeof(pg_tz *));
if (!*extra)
return false;
*((pg_tz **) *extra) = new_tz;
@@ -500,7 +500,7 @@ check_timezone_abbreviations(char **newval, void **extra, GucSource source)
return true;
}
- /* OK, load the file and produce a malloc'd TimeZoneAbbrevTable */
+ /* OK, load the file and produce a guc_malloc'd TimeZoneAbbrevTable */
*extra = load_tzoffsets(*newval);
/* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */
@@ -647,7 +647,7 @@ check_transaction_deferrable(bool *newval, void **extra, GucSource source)
bool
check_random_seed(double *newval, void **extra, GucSource source)
{
- *extra = malloc(sizeof(int));
+ *extra = guc_malloc(LOG, sizeof(int));
if (!*extra)
return false;
/* Arm the assign only if source of value is an interactive SET */
@@ -735,8 +735,8 @@ check_client_encoding(char **newval, void **extra, GucSource source)
if (strcmp(*newval, canonical_name) != 0 &&
strcmp(*newval, "UNICODE") != 0)
{
- free(*newval);
- *newval = strdup(canonical_name);
+ guc_free(*newval);
+ *newval = guc_strdup(LOG, canonical_name);
if (!*newval)
return false;
}
@@ -744,7 +744,7 @@ check_client_encoding(char **newval, void **extra, GucSource source)
/*
* Save the encoding's ID in *extra, for use by assign_client_encoding.
*/
- *extra = malloc(sizeof(int));
+ *extra = guc_malloc(LOG, sizeof(int));
if (!*extra)
return false;
*((int *) *extra) = encoding;
@@ -847,7 +847,7 @@ check_session_authorization(char **newval, void **extra, GucSource source)
ReleaseSysCache(roleTup);
/* Set up "extra" struct for assign_session_authorization to use */
- myextra = (role_auth_extra *) malloc(sizeof(role_auth_extra));
+ myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
if (!myextra)
return false;
myextra->roleid = roleid;
@@ -957,7 +957,7 @@ check_role(char **newval, void **extra, GucSource source)
}
/* Set up "extra" struct for assign_role to use */
- myextra = (role_auth_extra *) malloc(sizeof(role_auth_extra));
+ myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
if (!myextra)
return false;
myextra->roleid = roleid;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 383bc4776ef..30fb576ac37 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -849,8 +849,8 @@ PostmasterMain(int argc, char *argv[])
}
SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
- free(name);
- free(value);
+ pfree(name);
+ pfree(value);
break;
}
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e360d925b0d..1a022b11a06 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -1054,9 +1054,9 @@ check_synchronous_standby_names(char **newval, void **extra, GucSource source)
return false;
}
- /* GUC extra value must be malloc'd, not palloc'd */
+ /* GUC extra value must be guc_malloc'd, not palloc'd */
pconf = (SyncRepConfigData *)
- malloc(syncrep_parse_result->config_size);
+ guc_malloc(LOG, syncrep_parse_result->config_size);
if (pconf == NULL)
return false;
memcpy(pconf, syncrep_parse_result, syncrep_parse_result->config_size);
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 27dee29f420..a9a1851c946 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -3871,8 +3871,8 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx,
optarg)));
}
SetConfigOption(name, value, ctx, gucsource);
- free(name);
- free(value);
+ pfree(name);
+ pfree(value);
break;
}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 4e9935e01dd..74b68070984 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -29,6 +29,7 @@
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/datetime.h"
+#include "utils/guc.h"
#include "utils/memutils.h"
#include "utils/tzparser.h"
@@ -4782,8 +4783,8 @@ TemporalSimplify(int32 max_precis, Node *node)
* to create the final array of timezone tokens. The argument array
* is already sorted in name order.
*
- * The result is a TimeZoneAbbrevTable (which must be a single malloc'd chunk)
- * or NULL on malloc failure. No other error conditions are defined.
+ * The result is a TimeZoneAbbrevTable (which must be a single guc_malloc'd
+ * chunk) or NULL on alloc failure. No other error conditions are defined.
*/
TimeZoneAbbrevTable *
ConvertTimeZoneAbbrevs(struct tzEntry *abbrevs, int n)
@@ -4812,7 +4813,7 @@ ConvertTimeZoneAbbrevs(struct tzEntry *abbrevs, int n)
}
/* Alloc the result ... */
- tbl = malloc(tbl_size);
+ tbl = guc_malloc(LOG, tbl_size);
if (!tbl)
return NULL;
diff --git a/src/backend/utils/cache/ts_cache.c b/src/backend/utils/cache/ts_cache.c
index 890832f353c..450ea34336a 100644
--- a/src/backend/utils/cache/ts_cache.c
+++ b/src/backend/utils/cache/ts_cache.c
@@ -633,9 +633,9 @@ check_default_text_search_config(char **newval, void **extra, GucSource source)
ReleaseSysCache(tuple);
- /* GUC wants it malloc'd not palloc'd */
- free(*newval);
- *newval = strdup(buf);
+ /* GUC wants it guc_malloc'd not palloc'd */
+ guc_free(*newval);
+ *newval = guc_strdup(LOG, buf);
pfree(buf);
if (!*newval)
return false;
diff --git a/src/backend/utils/misc/README b/src/backend/utils/misc/README
index 6e294386f76..85d97d29b67 100644
--- a/src/backend/utils/misc/README
+++ b/src/backend/utils/misc/README
@@ -51,13 +51,13 @@ out-of-memory.
This might be used for example to canonicalize the spelling of a string
value, round off a buffer size to the nearest supported value, or replace
a special value such as "-1" with a computed default value. If the
-function wishes to replace a string value, it must malloc (not palloc)
-the replacement value, and be sure to free() the previous value.
+function wishes to replace a string value, it must guc_malloc (not palloc)
+the replacement value, and be sure to guc_free() the previous value.
* Derived information, such as the role OID represented by a user name,
-can be stored for use by the assign hook. To do this, malloc (not palloc)
+can be stored for use by the assign hook. To do this, guc_malloc (not palloc)
storage space for the information, and return its address at *extra.
-guc.c will automatically free() this space when the associated GUC setting
+guc.c will automatically guc_free() this space when the associated GUC setting
is no longer of interest. *extra is initialized to NULL before call, so
it can be ignored if not needed.
@@ -255,10 +255,9 @@ maintained by GUC.
GUC Memory Handling
-------------------
-String variable values are allocated with malloc/strdup, not with the
-palloc/pstrdup mechanisms. We would need to keep them in a permanent
-context anyway, and malloc gives us more control over handling
-out-of-memory failures.
+String variable values are allocated with guc_malloc or guc_strdup,
+which ensure that the values are kept in a long-lived context, and provide
+more control over handling out-of-memory failures than bare palloc.
We allow a string variable's actual value, reset_val, boot_val, and stacked
values to point at the same storage. This makes it slightly harder to free
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index f997ec0f822..3a4c4814a7a 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -188,6 +188,9 @@ static const char *const map_old_guc_names[] = {
};
+/* Memory context holding all GUC-related data */
+static MemoryContext GUCMemoryContext;
+
/*
* Actual lookup of variables is done through this single, sorted array.
*/
@@ -595,19 +598,22 @@ bail_out:
return head;
}
+
/*
- * Some infrastructure for checking malloc/strdup/realloc calls
+ * Some infrastructure for GUC-related memory allocation
+ *
+ * These functions are generally modeled on libc's malloc/realloc/etc,
+ * but any OOM issue is reported at the specified elevel.
+ * (Thus, control returns only if that's less than ERROR.)
*/
void *
guc_malloc(int elevel, size_t size)
{
void *data;
- /* Avoid unportable behavior of malloc(0) */
- if (size == 0)
- size = 1;
- data = malloc(size);
- if (data == NULL)
+ data = MemoryContextAllocExtended(GUCMemoryContext, size,
+ MCXT_ALLOC_NO_OOM);
+ if (unlikely(data == NULL))
ereport(elevel,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory")));
@@ -619,11 +625,20 @@ guc_realloc(int elevel, void *old, size_t size)
{
void *data;
- /* Avoid unportable behavior of realloc(NULL, 0) */
- if (old == NULL && size == 0)
- size = 1;
- data = realloc(old, size);
- if (data == NULL)
+ if (old != NULL)
+ {
+ /* This is to help catch old code that malloc's GUC data. */
+ Assert(GetMemoryChunkContext(old) == GUCMemoryContext);
+ data = repalloc_extended(old, size,
+ MCXT_ALLOC_NO_OOM);
+ }
+ else
+ {
+ /* Like realloc(3), but not like repalloc(), we allow old == NULL. */
+ data = MemoryContextAllocExtended(GUCMemoryContext, size,
+ MCXT_ALLOC_NO_OOM);
+ }
+ if (unlikely(data == NULL))
ereport(elevel,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory")));
@@ -634,15 +649,29 @@ char *
guc_strdup(int elevel, const char *src)
{
char *data;
+ size_t len = strlen(src) + 1;
- data = strdup(src);
- if (data == NULL)
- ereport(elevel,
- (errcode(ERRCODE_OUT_OF_MEMORY),
- errmsg("out of memory")));
+ data = guc_malloc(elevel, len);
+ if (likely(data != NULL))
+ memcpy(data, src, len);
return data;
}
+void
+guc_free(void *ptr)
+{
+ /*
+ * Historically, GUC-related code has relied heavily on the ability to do
+ * free(NULL), so we allow that here even though pfree() doesn't.
+ */
+ if (ptr != NULL)
+ {
+ /* This is to help catch old code that malloc's GUC data. */
+ Assert(GetMemoryChunkContext(ptr) == GUCMemoryContext);
+ pfree(ptr);
+ }
+}
+
/*
* Detect whether strval is referenced anywhere in a GUC string item
@@ -680,7 +709,7 @@ set_string_field(struct config_string *conf, char **field, char *newval)
/* Free old value if it's not NULL and isn't referenced anymore */
if (oldval && !string_field_used(conf, oldval))
- free(oldval);
+ guc_free(oldval);
}
/*
@@ -741,7 +770,7 @@ set_extra_field(struct config_generic *gconf, void **field, void *newval)
/* Free old value if it's not NULL and isn't referenced anymore */
if (oldval && !extra_field_used(gconf, oldval))
- free(oldval);
+ guc_free(oldval);
}
/*
@@ -749,7 +778,7 @@ set_extra_field(struct config_generic *gconf, void **field, void *newval)
* The "extra" field associated with the active value is copied, too.
*
* NB: be sure stringval and extra fields of a new stack entry are
- * initialized to NULL before this is used, else we'll try to free() them.
+ * initialized to NULL before this is used, else we'll try to guc_free() them.
*/
static void
set_stack_value(struct config_generic *gconf, config_var_value *val)
@@ -817,9 +846,9 @@ get_guc_variables(void)
/*
- * Build the sorted array. This is split out so that it could be
- * re-executed after startup (e.g., we could allow loadable modules to
- * add vars, and then we'd need to re-sort).
+ * Build the sorted array. This is split out so that help_config.c can
+ * extract all the variables without running all of InitializeGUCOptions.
+ * It's not meant for use anyplace else.
*/
void
build_guc_variables(void)
@@ -829,6 +858,17 @@ build_guc_variables(void)
struct config_generic **guc_vars;
int i;
+ /*
+ * Create the memory context that will hold all GUC-related data.
+ */
+ Assert(GUCMemoryContext == NULL);
+ GUCMemoryContext = AllocSetContextCreate(TopMemoryContext,
+ "GUCMemoryContext",
+ ALLOCSET_DEFAULT_SIZES);
+
+ /*
+ * Count all the built-in variables, and set their vartypes correctly.
+ */
for (i = 0; ConfigureNamesBool[i].gen.name; i++)
{
struct config_bool *conf = &ConfigureNamesBool[i];
@@ -895,7 +935,7 @@ build_guc_variables(void)
for (i = 0; ConfigureNamesEnum[i].gen.name; i++)
guc_vars[num_vars++] = &ConfigureNamesEnum[i].gen;
- free(guc_variables);
+ guc_free(guc_variables);
guc_variables = guc_vars;
num_guc_variables = num_vars;
size_guc_variables = size_vars;
@@ -1001,7 +1041,7 @@ add_placeholder_variable(const char *name, int elevel)
gen->name = guc_strdup(elevel, name);
if (gen->name == NULL)
{
- free(var);
+ guc_free(var);
return NULL;
}
@@ -1020,8 +1060,8 @@ add_placeholder_variable(const char *name, int elevel)
if (!add_guc_variable((struct config_generic *) var, elevel))
{
- free(unconstify(char *, gen->name));
- free(var);
+ guc_free(unconstify(char *, gen->name));
+ guc_free(var);
return NULL;
}
@@ -1255,7 +1295,7 @@ InitializeGUCOptions(void)
pg_timezone_initialize();
/*
- * Build sorted array of all GUC variables.
+ * Create GUCMemoryContext and build sorted array of all GUC variables.
*/
build_guc_variables();
@@ -1482,6 +1522,7 @@ SelectConfigFiles(const char *userDoption, const char *progname)
{
char *configdir;
char *fname;
+ bool fname_is_malloced;
struct stat stat_buf;
struct config_string *data_directory_rec;
@@ -1509,12 +1550,16 @@ SelectConfigFiles(const char *userDoption, const char *progname)
* the same way by future backends.
*/
if (ConfigFileName)
+ {
fname = make_absolute_path(ConfigFileName);
+ fname_is_malloced = true;
+ }
else if (configdir)
{
fname = guc_malloc(FATAL,
strlen(configdir) + strlen(CONFIG_FILENAME) + 2);
sprintf(fname, "%s/%s", configdir, CONFIG_FILENAME);
+ fname_is_malloced = false;
}
else
{
@@ -1530,7 +1575,11 @@ SelectConfigFiles(const char *userDoption, const char *progname)
* it can't be overridden later.
*/
SetConfigOption("config_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
- free(fname);
+
+ if (fname_is_malloced)
+ free(fname);
+ else
+ guc_free(fname);
/*
* Now read the config file for the first time.
@@ -1604,12 +1653,16 @@ SelectConfigFiles(const char *userDoption, const char *progname)
* Figure out where pg_hba.conf is, and make sure the path is absolute.
*/
if (HbaFileName)
+ {
fname = make_absolute_path(HbaFileName);
+ fname_is_malloced = true;
+ }
else if (configdir)
{
fname = guc_malloc(FATAL,
strlen(configdir) + strlen(HBA_FILENAME) + 2);
sprintf(fname, "%s/%s", configdir, HBA_FILENAME);
+ fname_is_malloced = false;
}
else
{
@@ -1621,18 +1674,26 @@ SelectConfigFiles(const char *userDoption, const char *progname)
return false;
}
SetConfigOption("hba_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
- free(fname);
+
+ if (fname_is_malloced)
+ free(fname);
+ else
+ guc_free(fname);
/*
* Likewise for pg_ident.conf.
*/
if (IdentFileName)
+ {
fname = make_absolute_path(IdentFileName);
+ fname_is_malloced = true;
+ }
else if (configdir)
{
fname = guc_malloc(FATAL,
strlen(configdir) + strlen(IDENT_FILENAME) + 2);
sprintf(fname, "%s/%s", configdir, IDENT_FILENAME);
+ fname_is_malloced = false;
}
else
{
@@ -1644,7 +1705,11 @@ SelectConfigFiles(const char *userDoption, const char *progname)
return false;
}
SetConfigOption("ident_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
- free(fname);
+
+ if (fname_is_malloced)
+ free(fname);
+ else
+ guc_free(fname);
free(configdir);
@@ -2289,12 +2354,12 @@ ReportGUCOption(struct config_generic *record)
pq_endmessage(&msgbuf);
/*
- * We need a long-lifespan copy. If strdup() fails due to OOM, we'll
- * set last_reported to NULL and thereby possibly make a duplicate
- * report later.
+ * We need a long-lifespan copy. If guc_strdup() fails due to OOM,
+ * we'll set last_reported to NULL and thereby possibly make a
+ * duplicate report later.
*/
- free(record->last_reported);
- record->last_reported = strdup(val);
+ guc_free(record->last_reported);
+ record->last_reported = guc_strdup(LOG, val);
}
pfree(val);
@@ -2893,7 +2958,7 @@ parse_and_validate_value(struct config_generic *record,
if (!call_string_check_hook(conf, &newval->stringval, newextra,
source, elevel))
{
- free(newval->stringval);
+ guc_free(newval->stringval);
newval->stringval = NULL;
return false;
}
@@ -3328,7 +3393,7 @@ set_config_option_ext(const char *name, const char *value,
{
/* Release newextra, unless it's reset_extra */
if (newextra && !extra_field_used(&conf->gen, newextra))
- free(newextra);
+ guc_free(newextra);
if (*conf->variable != newval)
{
@@ -3387,7 +3452,7 @@ set_config_option_ext(const char *name, const char *value,
/* Perhaps we didn't install newextra anywhere */
if (newextra && !extra_field_used(&conf->gen, newextra))
- free(newextra);
+ guc_free(newextra);
break;
#undef newval
@@ -3426,7 +3491,7 @@ set_config_option_ext(const char *name, const char *value,
{
/* Release newextra, unless it's reset_extra */
if (newextra && !extra_field_used(&conf->gen, newextra))
- free(newextra);
+ guc_free(newextra);
if (*conf->variable != newval)
{
@@ -3485,7 +3550,7 @@ set_config_option_ext(const char *name, const char *value,
/* Perhaps we didn't install newextra anywhere */
if (newextra && !extra_field_used(&conf->gen, newextra))
- free(newextra);
+ guc_free(newextra);
break;
#undef newval
@@ -3524,7 +3589,7 @@ set_config_option_ext(const char *name, const char *value,
{
/* Release newextra, unless it's reset_extra */
if (newextra && !extra_field_used(&conf->gen, newextra))
- free(newextra);
+ guc_free(newextra);
if (*conf->variable != newval)
{
@@ -3583,7 +3648,7 @@ set_config_option_ext(const char *name, const char *value,
/* Perhaps we didn't install newextra anywhere */
if (newextra && !extra_field_used(&conf->gen, newextra))
- free(newextra);
+ guc_free(newextra);
break;
#undef newval
@@ -3617,7 +3682,7 @@ set_config_option_ext(const char *name, const char *value,
if (!call_string_check_hook(conf, &newval, &newextra,
source, elevel))
{
- free(newval);
+ guc_free(newval);
return 0;
}
}
@@ -3645,10 +3710,10 @@ set_config_option_ext(const char *name, const char *value,
/* Release newval, unless it's reset_val */
if (newval && !string_field_used(conf, newval))
- free(newval);
+ guc_free(newval);
/* Release newextra, unless it's reset_extra */
if (newextra && !extra_field_used(&conf->gen, newextra))
- free(newextra);
+ guc_free(newextra);
if (newval_different)
{
@@ -3709,10 +3774,10 @@ set_config_option_ext(const char *name, const char *value,
/* Perhaps we didn't install newval anywhere */
if (newval && !string_field_used(conf, newval))
- free(newval);
+ guc_free(newval);
/* Perhaps we didn't install newextra anywhere */
if (newextra && !extra_field_used(&conf->gen, newextra))
- free(newextra);
+ guc_free(newextra);
break;
#undef newval
@@ -3751,7 +3816,7 @@ set_config_option_ext(const char *name, const char *value,
{
/* Release newextra, unless it's reset_extra */
if (newextra && !extra_field_used(&conf->gen, newextra))
- free(newextra);
+ guc_free(newextra);
if (*conf->variable != newval)
{
@@ -3810,7 +3875,7 @@ set_config_option_ext(const char *name, const char *value,
/* Perhaps we didn't install newextra anywhere */
if (newextra && !extra_field_used(&conf->gen, newextra))
- free(newextra);
+ guc_free(newextra);
break;
#undef newval
@@ -3848,7 +3913,7 @@ set_config_sourcefile(const char *name, char *sourcefile, int sourceline)
return;
sourcefile = guc_strdup(elevel, sourcefile);
- free(record->sourcefile);
+ guc_free(record->sourcefile);
record->sourcefile = sourcefile;
record->sourceline = sourceline;
}
@@ -4239,8 +4304,8 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
name, value)));
if (record->vartype == PGC_STRING && newval.stringval != NULL)
- free(newval.stringval);
- free(newextra);
+ guc_free(newval.stringval);
+ guc_free(newextra);
/*
* We must also reject values containing newlines, because the
@@ -4535,7 +4600,7 @@ define_custom_variable(struct config_generic *variable)
set_string_field(pHolder, pHolder->variable, NULL);
set_string_field(pHolder, &pHolder->reset_val, NULL);
- free(pHolder);
+ guc_free(pHolder);
}
/*
@@ -4814,7 +4879,7 @@ MarkGUCPrefixReserved(const char *className)
}
/* And remember the name so we can prevent future mistakes. */
- oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ oldcontext = MemoryContextSwitchTo(GUCMemoryContext);
reserved_class_prefix = lappend(reserved_class_prefix, pstrdup(className));
MemoryContextSwitchTo(oldcontext);
}
@@ -5287,9 +5352,9 @@ read_nondefault_variables(void)
if (varsourcefile[0])
set_config_sourcefile(varname, varsourcefile, varsourceline);
- free(varname);
- free(varvalue);
- free(varsourcefile);
+ guc_free(varname);
+ guc_free(varvalue);
+ guc_free(varsourcefile);
}
FreeFile(fp);
@@ -5731,9 +5796,9 @@ RestoreGUCState(void *gucstate)
* pointers.
*/
Assert(gconf->stack == NULL);
- free(gconf->extra);
- free(gconf->last_reported);
- free(gconf->sourcefile);
+ guc_free(gconf->extra);
+ guc_free(gconf->last_reported);
+ guc_free(gconf->sourcefile);
switch (gconf->vartype)
{
case PGC_BOOL:
@@ -5741,7 +5806,7 @@ RestoreGUCState(void *gucstate)
struct config_bool *conf = (struct config_bool *) gconf;
if (conf->reset_extra && conf->reset_extra != gconf->extra)
- free(conf->reset_extra);
+ guc_free(conf->reset_extra);
break;
}
case PGC_INT:
@@ -5749,7 +5814,7 @@ RestoreGUCState(void *gucstate)
struct config_int *conf = (struct config_int *) gconf;
if (conf->reset_extra && conf->reset_extra != gconf->extra)
- free(conf->reset_extra);
+ guc_free(conf->reset_extra);
break;
}
case PGC_REAL:
@@ -5757,18 +5822,18 @@ RestoreGUCState(void *gucstate)
struct config_real *conf = (struct config_real *) gconf;
if (conf->reset_extra && conf->reset_extra != gconf->extra)
- free(conf->reset_extra);
+ guc_free(conf->reset_extra);
break;
}
case PGC_STRING:
{
struct config_string *conf = (struct config_string *) gconf;
- free(*conf->variable);
+ guc_free(*conf->variable);
if (conf->reset_val && conf->reset_val != *conf->variable)
- free(conf->reset_val);
+ guc_free(conf->reset_val);
if (conf->reset_extra && conf->reset_extra != gconf->extra)
- free(conf->reset_extra);
+ guc_free(conf->reset_extra);
break;
}
case PGC_ENUM:
@@ -5776,7 +5841,7 @@ RestoreGUCState(void *gucstate)
struct config_enum *conf = (struct config_enum *) gconf;
if (conf->reset_extra && conf->reset_extra != gconf->extra)
- free(conf->reset_extra);
+ guc_free(conf->reset_extra);
break;
}
}
@@ -5838,7 +5903,7 @@ RestoreGUCState(void *gucstate)
/*
* A little "long argument" simulation, although not quite GNU
* compliant. Takes a string of the form "some-option=some value" and
- * returns name = "some_option" and value = "some value" in malloc'ed
+ * returns name = "some_option" and value = "some value" in palloc'ed
* storage. Note that '-' is converted to '_' in the option name. If
* there is no '=' in the input string then value will be NULL.
*/
@@ -5856,15 +5921,15 @@ ParseLongOption(const char *string, char **name, char **value)
if (string[equal_pos] == '=')
{
- *name = guc_malloc(FATAL, equal_pos + 1);
+ *name = palloc(equal_pos + 1);
strlcpy(*name, string, equal_pos + 1);
- *value = guc_strdup(FATAL, &string[equal_pos + 1]);
+ *value = pstrdup(&string[equal_pos + 1]);
}
else
{
/* no equal sign in string */
- *name = guc_strdup(FATAL, string);
+ *name = pstrdup(string);
*value = NULL;
}
@@ -5898,8 +5963,6 @@ ProcessGUCArray(ArrayType *array,
char *s;
char *name;
char *value;
- char *namecopy;
- char *valuecopy;
d = array_ref(array, 1, &i,
-1 /* varlenarray */ ,
@@ -5920,22 +5983,16 @@ ProcessGUCArray(ArrayType *array,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("could not parse setting for parameter \"%s\"",
name)));
- free(name);
+ pfree(name);
continue;
}
- /* free malloc'd strings immediately to avoid leak upon error */
- namecopy = pstrdup(name);
- free(name);
- valuecopy = pstrdup(value);
- free(value);
-
- (void) set_config_option(namecopy, valuecopy,
+ (void) set_config_option(name, value,
context, source,
action, true, 0, false);
- pfree(namecopy);
- pfree(valuecopy);
+ pfree(name);
+ pfree(value);
pfree(s);
}
}
@@ -6399,7 +6456,7 @@ call_string_check_hook(struct config_string *conf, char **newval, void **extra,
}
PG_CATCH();
{
- free(*newval);
+ guc_free(*newval);
PG_RE_THROW();
}
PG_END_TRY();
diff --git a/src/backend/utils/misc/tzparser.c b/src/backend/utils/misc/tzparser.c
index 8f2c95f0550..e291cb63b02 100644
--- a/src/backend/utils/misc/tzparser.c
+++ b/src/backend/utils/misc/tzparser.c
@@ -439,7 +439,7 @@ ParseTzFile(const char *filename, int depth,
* load_tzoffsets --- read and parse the specified timezone offset file
*
* On success, return a filled-in TimeZoneAbbrevTable, which must have been
- * malloc'd not palloc'd. On failure, return NULL, using GUC_check_errmsg
+ * guc_malloc'd not palloc'd. On failure, return NULL, using GUC_check_errmsg
* and friends to give details of the problem.
*/
TimeZoneAbbrevTable *
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 1788361974b..c8b65c5bb8f 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -401,6 +401,7 @@ extern ArrayType *GUCArrayReset(ArrayType *array);
extern void *guc_malloc(int elevel, size_t size);
extern pg_nodiscard void *guc_realloc(int elevel, void *old, size_t size);
extern char *guc_strdup(int elevel, const char *src);
+extern void guc_free(void *ptr);
#ifdef EXEC_BACKEND
extern void write_nondefault_variables(GucContext context);
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index 190d286f1c8..5dc334b61b3 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -114,7 +114,7 @@ plpgsql_extra_checks_check_hook(char **newvalue, void **extra, GucSource source)
list_free(elemlist);
}
- myextra = (int *) malloc(sizeof(int));
+ myextra = (int *) guc_malloc(LOG, sizeof(int));
if (!myextra)
return false;
*myextra = extrachecks;