diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index 22635f8094..58247d826d 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 b69ff37dbb..45b30ca566 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 e555fb3150..791bac6715 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 383bc4776e..30fb576ac3 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 e360d925b0..1a022b11a0 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 27dee29f42..a9a1851c94 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 4e9935e01d..74b6807098 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 890832f353..450ea34336 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 6e294386f7..85d97d29b6 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 f997ec0f82..3a4c4814a7 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 8f2c95f055..e291cb63b0 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 1788361974..c8b65c5bb8 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 190d286f1c..5dc334b61b 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;