From ab50ed8f57feb0f2fff30497115dbcc65175ed3a Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 5 Jul 2004 23:14:14 +0000 Subject: [PATCH] Fix unchecked mallocs/strdups added by recent placeholder-config-vars patch. Thomas Hallgren --- src/backend/utils/misc/guc.c | 205 ++++++++++++++++++++--------------- 1 file changed, 117 insertions(+), 88 deletions(-) diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index f5c16de83b..7e4f0ebc00 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut . * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.212 2004/07/01 00:51:24 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.213 2004/07/05 23:14:14 tgl Exp $ * *-------------------------------------------------------------------- */ @@ -1608,7 +1608,7 @@ static struct config_string ConfigureNamesString[] = gettext_noop("Sets the target for log output."), gettext_noop("Valid values are combinations of stderr, syslog " "and eventlog, depending on platform."), - GUC_LIST_INPUT | GUC_REPORT + GUC_LIST_INPUT }, &log_destination_string, "stderr", assign_log_destination, NULL @@ -1749,6 +1749,49 @@ static void ReportGUCOption(struct config_generic * record); static char *_ShowOption(struct config_generic * record); +/* + * Some infrastructure for checking malloc/strdup/realloc calls + */ +static void * +guc_malloc(int elevel, size_t size) +{ + void *data; + + data = malloc(size); + if (data == NULL) + ereport(elevel, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + return data; +} + +static void * +guc_realloc(int elevel, void *old, size_t size) +{ + void *data; + + data = realloc(old, size); + if (data == NULL) + ereport(elevel, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + return data; +} + +static char * +guc_strdup(int elevel, const char *src) +{ + char *data; + + data = strdup(src); + if (data == NULL) + ereport(elevel, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + return data; +} + + /* * Support for assigning to a field of a string GUC item. Free the prior * value if it's not referenced anywhere else in the item (including stacked @@ -1860,11 +1903,7 @@ build_guc_variables(void) size_vars = num_vars + num_vars / 4; guc_vars = (struct config_generic **) - malloc(size_vars * sizeof(struct config_generic *)); - if (!guc_vars) - ereport(FATAL, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); + guc_malloc(FATAL, size_vars * sizeof(struct config_generic *)); num_vars = 0; @@ -1923,28 +1962,30 @@ is_custom_class(const char *name, int dotPos) * Add a new GUC variable to the list of known variables. The * list is expanded if needed. */ -static void -add_guc_variable(struct config_generic *var) +static bool +add_guc_variable(struct config_generic *var, int elevel) { if(num_guc_variables + 1 >= size_guc_variables) { - /* Increase the vector with 20% + /* Increase the vector by 25% */ int size_vars = size_guc_variables + size_guc_variables / 4; struct config_generic** guc_vars; if(size_vars == 0) - size_vars = 100; - - guc_vars = (struct config_generic**) - malloc(size_vars * sizeof(struct config_generic*)); - - if (guc_variables != NULL) { - memcpy(guc_vars, guc_variables, - num_guc_variables * sizeof(struct config_generic*)); - free(guc_variables); + size_vars = 100; + guc_vars = (struct config_generic**) + guc_malloc(elevel, size_vars * sizeof(struct config_generic*)); } + else + { + guc_vars = (struct config_generic**) + guc_realloc(elevel, guc_variables, size_vars * sizeof(struct config_generic*)); + } + + if(guc_vars == NULL) + return false; /* out of memory */ guc_variables = guc_vars; size_guc_variables = size_vars; @@ -1952,22 +1993,34 @@ add_guc_variable(struct config_generic *var) guc_variables[num_guc_variables++] = var; qsort((void*) guc_variables, num_guc_variables, sizeof(struct config_generic*), guc_var_compare); + return true; } /* - * Create and add a placeholder variable. Its presumed to belong + * Create and add a placeholder variable. It's presumed to belong * to a valid custom variable class at this point. */ static struct config_string* -add_placeholder_variable(const char *name) +add_placeholder_variable(const char *name, int elevel) { size_t sz = sizeof(struct config_string) + sizeof(char*); - struct config_string* var = (struct config_string*)malloc(sz); - struct config_generic* gen = &var->gen; + struct config_string* var; + struct config_generic* gen; + var = (struct config_string*)guc_malloc(elevel, sz); + if(var == NULL) + return NULL; + + gen = &var->gen; memset(var, 0, sz); - gen->name = strdup(name); + gen->name = guc_strdup(elevel, name); + if(gen->name == NULL) + { + free(var); + return NULL; + } + gen->context = PGC_USERSET; gen->group = CUSTOM_OPTIONS; gen->short_desc = "GUC placeholder variable"; @@ -1978,7 +2031,14 @@ add_placeholder_variable(const char *name) * no 'static' place to point to. */ var->variable = (char**)(var + 1); - add_guc_variable((struct config_generic*)var); + + if(!add_guc_variable((struct config_generic*) var, elevel)) + { + free((void *) gen->name); + free(var); + return NULL; + } + return var; } @@ -1987,7 +2047,7 @@ add_placeholder_variable(const char *name) * else return NULL. */ static struct config_generic * -find_option(const char *name) +find_option(const char *name, int elevel) { const char *dot; const char **key = &name; @@ -2016,7 +2076,7 @@ find_option(const char *name) for (i = 0; map_old_guc_names[i] != NULL; i += 2) { if (guc_name_compare(name, map_old_guc_names[i]) == 0) - return find_option(map_old_guc_names[i+1]); + return find_option(map_old_guc_names[i+1], elevel); } /* @@ -2026,7 +2086,7 @@ find_option(const char *name) dot = strchr(name, GUC_QUALIFIER_SEPARATOR); if(dot != NULL && is_custom_class(name, dot - name)) /* Add a placeholder variable for this name */ - return (struct config_generic*)add_placeholder_variable(name); + return (struct config_generic*)add_placeholder_variable(name, elevel); /* Unknown name */ return NULL; @@ -2172,11 +2232,7 @@ InitializeGUCOptions(void) break; } - str = strdup(conf->boot_val); - if (str == NULL) - ereport(FATAL, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); + str = guc_strdup(FATAL, conf->boot_val); conf->reset_val = str; if (conf->assign_hook) @@ -2912,7 +2968,7 @@ set_config_option(const char *name, const char *value, else elevel = ERROR; - record = find_option(name); + record = find_option(name, elevel); if (record == NULL) { ereport(elevel, @@ -3368,14 +3424,9 @@ set_config_option(const char *name, const char *value, if (value) { - newval = strdup(value); + newval = guc_strdup(elevel, value); if (newval == NULL) - { - ereport(elevel, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); return false; - } if (record->context == PGC_USERLIMIT) { @@ -3426,14 +3477,9 @@ set_config_option(const char *name, const char *value, * make this case work the same as the normal * assignment case. */ - newval = strdup(conf->reset_val); + newval = guc_strdup(elevel, conf->reset_val); if (newval == NULL) - { - ereport(elevel, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); return false; - } source = conf->gen.reset_source; } else @@ -3571,7 +3617,7 @@ GetConfigOption(const char *name) struct config_generic *record; static char buffer[256]; - record = find_option(name); + record = find_option(name, ERROR); if (record == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), @@ -3607,7 +3653,7 @@ GetConfigOptionResetString(const char *name) struct config_generic *record; static char buffer[256]; - record = find_option(name); + record = find_option(name, ERROR); if (record == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), @@ -3663,7 +3709,7 @@ flatten_set_variable_args(const char *name, List *args) return NULL; /* Else get flags for the variable */ - record = find_option(name); + record = find_option(name, ERROR); if (record == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), @@ -3834,7 +3880,7 @@ define_custom_variable(struct config_generic* variable) if(res == NULL) { - add_guc_variable(variable); + add_guc_variable(variable, ERROR); return; } @@ -3883,7 +3929,7 @@ static void init_custom_variable( GucContext context, enum config_type type) { - gen->name = strdup(name); + gen->name = guc_strdup(ERROR, name); gen->context = context; gen->group = CUSTOM_OPTIONS; gen->short_desc = short_desc; @@ -3901,7 +3947,7 @@ void DefineCustomBoolVariable( GucShowHook show_hook) { size_t sz = sizeof(struct config_bool); - struct config_bool* var = (struct config_bool*)malloc(sz); + struct config_bool* var = (struct config_bool*)guc_malloc(ERROR, sz); memset(var, 0, sz); init_custom_variable(&var->gen, name, short_desc, long_desc, context, PGC_BOOL); @@ -3923,7 +3969,7 @@ void DefineCustomIntVariable( GucShowHook show_hook) { size_t sz = sizeof(struct config_int); - struct config_int* var = (struct config_int*)malloc(sz); + struct config_int* var = (struct config_int*)guc_malloc(ERROR, sz); memset(var, 0, sz); init_custom_variable(&var->gen, name, short_desc, long_desc, context, PGC_INT); @@ -3945,7 +3991,7 @@ void DefineCustomRealVariable( GucShowHook show_hook) { size_t sz = sizeof(struct config_real); - struct config_real* var = (struct config_real*)malloc(sz); + struct config_real* var = (struct config_real*)guc_malloc(ERROR, sz); memset(var, 0, sz); init_custom_variable(&var->gen, name, short_desc, long_desc, context, PGC_REAL); @@ -3967,7 +4013,7 @@ void DefineCustomStringVariable( GucShowHook show_hook) { size_t sz = sizeof(struct config_string); - struct config_string* var = (struct config_string*)malloc(sz); + struct config_string* var = (struct config_string*)guc_malloc(ERROR, sz); memset(var, 0, sz); init_custom_variable(&var->gen, name, short_desc, long_desc, context, PGC_STRING); @@ -4139,7 +4185,7 @@ GetConfigOptionByName(const char *name, const char **varname) { struct config_generic *record; - record = find_option(name); + record = find_option(name, ERROR); if (record == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), @@ -4506,16 +4552,18 @@ write_nondefault_variables(GucContext context) /* * Open file */ - new_filename = malloc(strlen(DataDir) + strlen(CONFIG_EXEC_PARAMS) + + new_filename = guc_malloc(elevel, strlen(DataDir) + strlen(CONFIG_EXEC_PARAMS) + strlen(".new") + 2); - filename = malloc(strlen(DataDir) + strlen(CONFIG_EXEC_PARAMS) + 2); - if (new_filename == NULL || filename == NULL) + if(new_filename == NULL) + return; + + filename = guc_malloc(elevel, strlen(DataDir) + strlen(CONFIG_EXEC_PARAMS) + 2); + if (filename == NULL) { - ereport(elevel, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); + free(new_filename); return; } + sprintf(new_filename, "%s/" CONFIG_EXEC_PARAMS ".new", DataDir); sprintf(filename, "%s/" CONFIG_EXEC_PARAMS, DataDir); @@ -4627,9 +4675,9 @@ read_string_with_null(FILE *fp) elog(FATAL, "invalid format of exec config params file"); } if (i == 0) - str = malloc(maxlen); + str = guc_malloc(FATAL, maxlen); else if (i == maxlen) - str = realloc(str, maxlen *= 2); + str = guc_realloc(FATAL, str, maxlen *= 2); str[i++] = ch; } while (ch != 0); @@ -4655,14 +4703,7 @@ read_nondefault_variables(void) /* * Open file */ - filename = malloc(strlen(DataDir) + strlen(CONFIG_EXEC_PARAMS) + 2); - if (filename == NULL) - { - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); - return; - } + filename = guc_malloc(FATAL, strlen(DataDir) + strlen(CONFIG_EXEC_PARAMS) + 2); sprintf(filename, "%s/" CONFIG_EXEC_PARAMS, DataDir); fp = AllocateFile(filename, "r"); @@ -4684,7 +4725,7 @@ read_nondefault_variables(void) if ((varname = read_string_with_null(fp)) == NULL) break; - if ((record = find_option(varname)) == NULL) + if ((record = find_option(varname, FATAL)) == NULL) elog(FATAL, "failed to locate variable %s in exec config params file",varname); if ((varvalue = read_string_with_null(fp)) == NULL) elog(FATAL, "invalid format of exec config params file"); @@ -4725,28 +4766,16 @@ ParseLongOption(const char *string, char **name, char **value) if (string[equal_pos] == '=') { - *name = malloc(equal_pos + 1); - if (!*name) - ereport(FATAL, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); + *name = guc_malloc(FATAL, equal_pos + 1); strncpy(*name, string, equal_pos); (*name)[equal_pos] = '\0'; - *value = strdup(&string[equal_pos + 1]); - if (!*value) - ereport(FATAL, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); + *value = guc_strdup(FATAL, &string[equal_pos + 1]); } else { /* no equal sign in string */ - *name = strdup(string); - if (!*name) - ereport(FATAL, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); + *name = guc_strdup(FATAL, string); *value = NULL; }