Commit 65c99207 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-23841: Memory leak in innodb_monitor_validate()

innodb_monitor_validate(): Let item_val_str() allocate the memory
in THD, so that it will be available to innodb_monitor_update().
In this way, there is no need to allocate another buffer, and
no problem if the call to innodb_monitor_update() is skipped due
to an invalid value that is passed to another configuration parameter.

There are some other callers to st_mysql_sys_var::val_str()
that validate configuration parameters that are related to FULLTEXT INDEX,
but they will allocate memory by invoking thd_strmake().
parent 5299f0c4
...@@ -637,6 +637,8 @@ LIKE 'buffer_page_written_index_leaf'; ...@@ -637,6 +637,8 @@ LIKE 'buffer_page_written_index_leaf';
NAME COUNT > 0 NAME COUNT > 0
buffer_page_written_index_leaf 0 buffer_page_written_index_leaf 0
SET GLOBAL innodb_monitor_enable='%'; SET GLOBAL innodb_monitor_enable='%';
SET GLOBAL innodb_monitor_reset_all= '%', innodb_compression_algorithm= foo;
ERROR 42000: Variable 'innodb_compression_algorithm' can't be set to the value of 'foo'
INSERT INTO t1 VALUES (5), (6), (7), (8); INSERT INTO t1 VALUES (5), (6), (7), (8);
FLUSH TABLES t1 FOR EXPORT; FLUSH TABLES t1 FOR EXPORT;
UNLOCK TABLES; UNLOCK TABLES;
......
...@@ -408,6 +408,8 @@ SELECT NAME, COUNT > 0 FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME ...@@ -408,6 +408,8 @@ SELECT NAME, COUNT > 0 FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME
LIKE 'buffer_page_written_index_leaf'; LIKE 'buffer_page_written_index_leaf';
SET GLOBAL innodb_monitor_enable='%'; SET GLOBAL innodb_monitor_enable='%';
--error ER_WRONG_VALUE_FOR_VAR
SET GLOBAL innodb_monitor_reset_all= '%', innodb_compression_algorithm= foo;
INSERT INTO t1 VALUES (5), (6), (7), (8); FLUSH TABLES t1 FOR EXPORT; INSERT INTO t1 VALUES (5), (6), (7), (8); FLUSH TABLES t1 FOR EXPORT;
UNLOCK TABLES; UNLOCK TABLES;
SELECT NAME, COUNT > 0 FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME SELECT NAME, COUNT > 0 FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME
......
...@@ -17808,13 +17808,7 @@ innodb_monitor_validate_wildcard_name( ...@@ -17808,13 +17808,7 @@ innodb_monitor_validate_wildcard_name(
Validate the passed in monitor name, find and save the Validate the passed in monitor name, find and save the
corresponding monitor name in the function parameter "save". corresponding monitor name in the function parameter "save".
@return 0 if monitor name is valid */ @return 0 if monitor name is valid */
static static int innodb_monitor_valid_byname(const char *name)
int
innodb_monitor_valid_byname(
/*========================*/
void* save, /*!< out: immediate result
for update function */
const char* name) /*!< in: incoming monitor name */
{ {
ulint use; ulint use;
monitor_info_t* monitor_info; monitor_info_t* monitor_info;
...@@ -17862,9 +17856,6 @@ innodb_monitor_valid_byname( ...@@ -17862,9 +17856,6 @@ innodb_monitor_valid_byname(
} }
} }
/* Save the configure name for innodb_monitor_update() */
*static_cast<const char**>(save) = name;
return(0); return(0);
} }
/*************************************************************//** /*************************************************************//**
...@@ -17880,41 +17871,18 @@ innodb_monitor_validate( ...@@ -17880,41 +17871,18 @@ innodb_monitor_validate(
for update function */ for update function */
struct st_mysql_value* value) /*!< in: incoming string */ struct st_mysql_value* value) /*!< in: incoming string */
{ {
const char* name; int ret= 0;
char* monitor_name;
char buff[STRING_BUFFER_USUAL_SIZE];
int len = sizeof(buff);
int ret;
ut_a(save != NULL); if (const char *name= value->val_str(value, nullptr, &ret))
ut_a(value != NULL); {
ret= innodb_monitor_valid_byname(name);
name = value->val_str(value, buff, &len); if (!ret)
*static_cast<const char**>(save)= name;
/* monitor_name could point to memory from MySQL }
or buff[]. Always dup the name to memory allocated else
by InnoDB, so we can access it in another callback ret= 1;
function innodb_monitor_update() and free it appropriately */
if (name) {
monitor_name = my_strdup(//PSI_INSTRUMENT_ME,
name, MYF(0));
} else {
return(1);
}
ret = innodb_monitor_valid_byname(save, monitor_name);
if (ret) {
/* Validation failed */
my_free(monitor_name);
} else {
/* monitor_name will be freed in separate callback function
innodb_monitor_update(). Assert "save" point to
the "monitor_name" variable */
ut_ad(*static_cast<char**>(save) == monitor_name);
}
return(ret); return ret;
} }
/****************************************************************//** /****************************************************************//**
...@@ -17930,11 +17898,9 @@ innodb_monitor_update( ...@@ -17930,11 +17898,9 @@ innodb_monitor_update(
formal string goes */ formal string goes */
const void* save, /*!< in: immediate result const void* save, /*!< in: immediate result
from check function */ from check function */
mon_option_t set_option, /*!< in: the set option, mon_option_t set_option) /*!< in: the set option,
whether to turn on/off or whether to turn on/off or
reset the counter */ reset the counter */
ibool free_mem) /*!< in: whether we will
need to free the memory */
{ {
monitor_info_t* monitor_info; monitor_info_t* monitor_info;
ulint monitor_id; ulint monitor_id;
...@@ -18018,12 +17984,6 @@ innodb_monitor_update( ...@@ -18018,12 +17984,6 @@ innodb_monitor_update(
sql_print_warning("InnoDB: Monitor %s is already enabled.", sql_print_warning("InnoDB: Monitor %s is already enabled.",
srv_mon_get_name((monitor_id_t) err_monitor)); srv_mon_get_name((monitor_id_t) err_monitor));
} }
if (free_mem && name) {
my_free((void*) name);
}
return;
} }
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
...@@ -18114,7 +18074,7 @@ innodb_enable_monitor_update( ...@@ -18114,7 +18074,7 @@ innodb_enable_monitor_update(
const void* save) /*!< in: immediate result const void* save) /*!< in: immediate result
from check function */ from check function */
{ {
innodb_monitor_update(thd, var_ptr, save, MONITOR_TURN_ON, TRUE); innodb_monitor_update(thd, var_ptr, save, MONITOR_TURN_ON);
} }
/****************************************************************//** /****************************************************************//**
...@@ -18131,7 +18091,7 @@ innodb_disable_monitor_update( ...@@ -18131,7 +18091,7 @@ innodb_disable_monitor_update(
const void* save) /*!< in: immediate result const void* save) /*!< in: immediate result
from check function */ from check function */
{ {
innodb_monitor_update(thd, var_ptr, save, MONITOR_TURN_OFF, TRUE); innodb_monitor_update(thd, var_ptr, save, MONITOR_TURN_OFF);
} }
/****************************************************************//** /****************************************************************//**
...@@ -18149,7 +18109,7 @@ innodb_reset_monitor_update( ...@@ -18149,7 +18109,7 @@ innodb_reset_monitor_update(
const void* save) /*!< in: immediate result const void* save) /*!< in: immediate result
from check function */ from check function */
{ {
innodb_monitor_update(thd, var_ptr, save, MONITOR_RESET_VALUE, TRUE); innodb_monitor_update(thd, var_ptr, save, MONITOR_RESET_VALUE);
} }
/****************************************************************//** /****************************************************************//**
...@@ -18167,8 +18127,7 @@ innodb_reset_all_monitor_update( ...@@ -18167,8 +18127,7 @@ innodb_reset_all_monitor_update(
const void* save) /*!< in: immediate result const void* save) /*!< in: immediate result
from check function */ from check function */
{ {
innodb_monitor_update(thd, var_ptr, save, MONITOR_RESET_ALL_VALUE, innodb_monitor_update(thd, var_ptr, save, MONITOR_RESET_ALL_VALUE);
TRUE);
} }
static static
...@@ -18213,10 +18172,9 @@ innodb_enable_monitor_at_startup( ...@@ -18213,10 +18172,9 @@ innodb_enable_monitor_at_startup(
for (char* option = my_strtok_r(str, sep, &last); for (char* option = my_strtok_r(str, sep, &last);
option; option;
option = my_strtok_r(NULL, sep, &last)) { option = my_strtok_r(NULL, sep, &last)) {
char* option_name; if (!innodb_monitor_valid_byname(option)) {
if (!innodb_monitor_valid_byname(&option_name, option)) {
innodb_monitor_update(NULL, NULL, &option, innodb_monitor_update(NULL, NULL, &option,
MONITOR_TURN_ON, FALSE); MONITOR_TURN_ON);
} else { } else {
sql_print_warning("Invalid monitor counter" sql_print_warning("Invalid monitor counter"
" name: '%s'", option); " name: '%s'", option);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment