summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Kopytov <Alexey.Kopytov@Sun.com>2010-06-11 17:48:24 +0400
committerAlexey Kopytov <Alexey.Kopytov@Sun.com>2010-06-11 17:48:24 +0400
commitf84b3f5c21c62ebe3b489250a09aca0ffde1313c (patch)
treebad36a3866fc1f57ed09d6de5a590fa2e12bacfe
parent26a034959299cb72d04d92ab330dfb83ef6082a6 (diff)
parente5cf56ef80391caca2f06b34fc1de1313196e91f (diff)
downloadmariadb-git-f84b3f5c21c62ebe3b489250a09aca0ffde1313c.tar.gz
Manual merge from mysql-5.1-bugteam to mysql-trunk-merge.
conflicts: conflict mysys/safemalloc.c conflict sql/mysqld.cc conflict sql/sp.cc conflict sql/sql_lex.cc conflict sql/sql_lex.h conflict sql/sql_parse.cc conflict sql/sql_prepare.cc
-rw-r--r--mysql-test/r/error_simulation.result9
-rw-r--r--mysql-test/t/error_simulation.test14
-rw-r--r--mysys/my_alloc.c16
-rw-r--r--mysys/my_malloc.c12
-rw-r--r--mysys/safemalloc.c7
-rw-r--r--sql/event_data_objects.cc5
-rw-r--r--sql/log_event.cc9
-rw-r--r--sql/mysqld.cc4
-rw-r--r--sql/sp.cc9
-rw-r--r--sql/sql_class.cc3
-rw-r--r--sql/sql_lex.cc30
-rw-r--r--sql/sql_lex.h32
-rw-r--r--sql/sql_parse.cc30
-rw-r--r--sql/sql_partition.cc4
-rw-r--r--sql/sql_prepare.cc21
-rw-r--r--sql/sql_trigger.cc6
-rw-r--r--sql/sql_view.cc7
-rw-r--r--sql/thr_malloc.cc8
18 files changed, 179 insertions, 47 deletions
diff --git a/mysql-test/r/error_simulation.result b/mysql-test/r/error_simulation.result
index 27e51a33112..fc58687cc86 100644
--- a/mysql-test/r/error_simulation.result
+++ b/mysql-test/r/error_simulation.result
@@ -39,5 +39,14 @@ a
2
DROP TABLE t1;
#
+# Bug#42064: low memory crash when importing hex strings, in Item_hex_string::Item_hex_string
+#
+CREATE TABLE t1(a BLOB);
+SET SESSION debug="+d,bug42064_simulate_oom";
+INSERT INTO t1 VALUES("");
+Got one of the listed errors
+SET SESSION debug=DEFAULT;
+DROP TABLE t1;
+#
# End of 5.1 tests
#
diff --git a/mysql-test/t/error_simulation.test b/mysql-test/t/error_simulation.test
index 7cd16a6bc5a..7a48a2e3231 100644
--- a/mysql-test/t/error_simulation.test
+++ b/mysql-test/t/error_simulation.test
@@ -47,5 +47,19 @@ DROP TABLE t1;
--echo #
+--echo # Bug#42064: low memory crash when importing hex strings, in Item_hex_string::Item_hex_string
+--echo #
+
+CREATE TABLE t1(a BLOB);
+
+SET SESSION debug="+d,bug42064_simulate_oom";
+# May fail with either ER_OUT_OF_RESOURCES or EE_OUTOFMEMORY
+--error ER_OUT_OF_RESOURCES, 5
+INSERT INTO t1 VALUES("");
+SET SESSION debug=DEFAULT;
+
+DROP TABLE t1;
+
+--echo #
--echo # End of 5.1 tests
--echo #
diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c
index 9c45cdc2277..19e51880209 100644
--- a/mysys/my_alloc.c
+++ b/mysys/my_alloc.c
@@ -154,6 +154,14 @@ void *alloc_root(MEM_ROOT *mem_root, size_t length)
DBUG_ASSERT(alloc_root_inited(mem_root));
+ DBUG_EXECUTE_IF("simulate_out_of_memory",
+ {
+ if (mem_root->error_handler)
+ (*mem_root->error_handler)();
+ DBUG_SET("-d,simulate_out_of_memory");
+ DBUG_RETURN((void*) 0); /* purecov: inspected */
+ });
+
length+=ALIGN_SIZE(sizeof(USED_MEM));
if (!(next = (USED_MEM*) my_malloc(length,MYF(MY_WME | ME_FATALERROR))))
{
@@ -176,6 +184,14 @@ void *alloc_root(MEM_ROOT *mem_root, size_t length)
DBUG_PRINT("enter",("root: 0x%lx", (long) mem_root));
DBUG_ASSERT(alloc_root_inited(mem_root));
+ DBUG_EXECUTE_IF("simulate_out_of_memory",
+ {
+ /* Avoid reusing an already allocated block */
+ if (mem_root->error_handler)
+ (*mem_root->error_handler)();
+ DBUG_SET("-d,simulate_out_of_memory");
+ DBUG_RETURN((void*) 0); /* purecov: inspected */
+ });
length= ALIGN_SIZE(length);
if ((*(prev= &mem_root->free)) != NULL)
{
diff --git a/mysys/my_malloc.c b/mysys/my_malloc.c
index 12793ad451b..13d2375eb99 100644
--- a/mysys/my_malloc.c
+++ b/mysys/my_malloc.c
@@ -31,13 +31,23 @@ void *my_malloc(size_t size, myf my_flags)
if (!size)
size=1; /* Safety */
- if ((point = (char*)malloc(size)) == NULL)
+
+ point= (char *) malloc(size);
+ DBUG_EXECUTE_IF("simulate_out_of_memory",
+ {
+ free(point);
+ point= NULL;
+ });
+
+ if (point == NULL)
{
my_errno=errno;
if (my_flags & MY_FAE)
error_handler_hook=fatal_error_handler_hook;
if (my_flags & (MY_FAE+MY_WME))
my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG+ME_NOREFRESH),size);
+ DBUG_EXECUTE_IF("simulate_out_of_memory",
+ DBUG_SET("-d,simulate_out_of_memory"););
if (my_flags & MY_FAE)
exit(1);
}
diff --git a/mysys/safemalloc.c b/mysys/safemalloc.c
index 936248677f5..6d0f7e5dd53 100644
--- a/mysys/safemalloc.c
+++ b/mysys/safemalloc.c
@@ -139,6 +139,11 @@ void *_mymalloc(size_t size, const char *filename, uint lineno, myf MyFlags)
size + /* size requested */
4 + /* overrun mark */
sf_malloc_endhunc);
+ DBUG_EXECUTE_IF("simulate_out_of_memory",
+ {
+ free(irem);
+ irem= NULL;
+ });
}
/* Check if there isn't anymore memory avaiable */
if (!irem)
@@ -159,6 +164,8 @@ void *_mymalloc(size_t size, const char *filename, uint lineno, myf MyFlags)
}
DBUG_PRINT("error",("Out of memory, in use: %ld at line %d, '%s'",
(long)sf_malloc_max_memory,lineno, filename));
+ DBUG_EXECUTE_IF("simulate_out_of_memory",
+ DBUG_SET("-d,simulate_out_of_memory"););
if (MyFlags & MY_FAE)
exit(1);
DBUG_RETURN ((void*) 0);
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index 28fd1e240a2..c778d72a016 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -1447,7 +1447,10 @@ Event_job_data::execute(THD *thd, bool drop)
thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length());
{
- Parser_state parser_state(thd, thd->query(), thd->query_length());
+ Parser_state parser_state;
+ if (parser_state.init(thd, thd->query(), thd->query_length()))
+ goto end;
+
lex_start(thd);
if (parse_sql(thd, & parser_state, creation_ctx))
diff --git a/sql/log_event.cc b/sql/log_event.cc
index cefc49f8c8a..7778ee18f5c 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -3254,9 +3254,12 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
thd->table_map_for_update= (table_map)table_map_for_update;
/* Execute the query (note that we bypass dispatch_command()) */
- Parser_state parser_state(thd, thd->query(), thd->query_length());
- mysql_parse(thd, thd->query(), thd->query_length(), &parser_state);
- log_slow_statement(thd);
+ Parser_state parser_state;
+ if (!parser_state.init(thd, thd->query(), thd->query_length()))
+ {
+ mysql_parse(thd, thd->query(), thd->query_length(), &parser_state);
+ log_slow_statement(thd);
+ }
/*
Resetting the enable_slow_log thd variable.
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 5c2f210f93a..fbb497ed2cd 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3113,6 +3113,10 @@ void my_message_sql(uint error, const char *str, myf MyFlags)
MYSQL_ERROR::WARN_LEVEL_ERROR,
str);
}
+
+ /* When simulating OOM, skip writing to error log to avoid mtr errors */
+ DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_VOID_RETURN;);
+
if (!thd || MyFlags & ME_NOREFRESH)
sql_print_error("%s: %s",my_progname,str); /* purecov: inspected */
DBUG_VOID_RETURN;
diff --git a/sql/sp.cc b/sql/sp.cc
index 57209c918cf..5328471f4c0 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -720,11 +720,18 @@ static sp_head *sp_compile(THD *thd, String *defstr, ulong sql_mode,
ha_rows old_select_limit= thd->variables.select_limit;
sp_rcontext *old_spcont= thd->spcont;
Silence_deprecated_warning warning_handler;
+ Parser_state parser_state;
thd->variables.sql_mode= sql_mode;
thd->variables.select_limit= HA_POS_ERROR;
- Parser_state parser_state(thd, defstr->c_ptr(), defstr->length());
+ if (parser_state.init(thd, defstr->c_ptr(), defstr->length()))
+ {
+ thd->variables.sql_mode= old_sql_mode;
+ thd->variables.select_limit= old_select_limit;
+ return NULL;
+ }
+
lex_start(thd);
thd->push_internal_handler(&warning_handler);
thd->spcont= 0;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index ac092756a74..8c147421363 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -878,6 +878,9 @@ THD::raise_condition_no_handler(uint sql_errno,
if (no_warnings_for_error && (level == MYSQL_ERROR::WARN_LEVEL_ERROR))
DBUG_RETURN(NULL);
+ /* When simulating OOM, skip writing to error log to avoid mtr errors */
+ DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_RETURN(NULL););
+
cond= warning_info->push_warning(this, sql_errno, sqlstate, level, msg);
DBUG_RETURN(cond);
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 82aa004a751..16b4c727689 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -147,20 +147,30 @@ st_parsing_options::reset()
Perform initialization of Lex_input_stream instance.
Basically, a buffer for pre-processed query. This buffer should be large
- enough to keep multi-statement query. The allocation is done once in the
- Lex_input_stream constructor in order to prevent memory pollution when
+ enough to keep multi-statement query. The allocation is done once in
+ Lex_input_stream::init() in order to prevent memory pollution when
the server is processing large multi-statement queries.
-
- @todo Check return value of THD::alloc().
*/
-Lex_input_stream::Lex_input_stream(THD *thd,
- const char* buffer,
- unsigned int length)
- :m_thd(thd)
+bool Lex_input_stream::init(THD *thd,
+ const char* buff,
+ unsigned int length)
{
+ DBUG_EXECUTE_IF("bug42064_simulate_oom",
+ DBUG_SET("+d,simulate_out_of_memory"););
+
m_cpp_buf= (char*) thd->alloc(length + 1);
- reset(buffer, length);
+
+ DBUG_EXECUTE_IF("bug42064_simulate_oom",
+ DBUG_SET("-d,bug42064_simulate_oom"););
+
+ if (m_cpp_buf == NULL)
+ return TRUE;
+
+ m_thd= thd;
+ reset(buff, length);
+
+ return FALSE;
}
@@ -203,8 +213,6 @@ Lex_input_stream::reset(const char *buffer, unsigned int length)
m_cpp_ptr= m_cpp_buf;
}
-Lex_input_stream::~Lex_input_stream()
-{}
/**
The operation is called from the parser in order to
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index eb3d9223a74..985edd42496 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1378,8 +1378,21 @@ enum enum_comment_state
class Lex_input_stream
{
public:
- Lex_input_stream(THD *thd, const char* buff, unsigned int length);
- ~Lex_input_stream();
+ Lex_input_stream()
+ {
+ }
+
+ ~Lex_input_stream()
+ {
+ }
+
+ /**
+ Object initializer. Must be called before usage.
+
+ @retval FALSE OK
+ @retval TRUE Error
+ */
+ bool init(THD *thd, const char *buff, unsigned int length);
void reset(const char *buff, unsigned int length);
@@ -2317,10 +2330,21 @@ public:
class Parser_state
{
public:
- Parser_state(THD *thd, const char* buff, unsigned int length)
- : m_lip(thd, buff, length), m_yacc()
+ Parser_state()
+ : m_yacc()
{}
+ /**
+ Object initializer. Must be called before usage.
+
+ @retval FALSE OK
+ @retval TRUE Error
+ */
+ bool init(THD *thd, const char *buff, unsigned int length)
+ {
+ return m_lip.init(thd, buff, length);
+ }
+
~Parser_state()
{}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 77d7fefb1b5..bdee13372d5 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -559,7 +559,14 @@ static void handle_bootstrap_impl(THD *thd)
mode we have only one thread.
*/
thd->set_time();
- Parser_state parser_state(thd, thd->query(), length);
+ Parser_state parser_state;
+ if (parser_state.init(thd, thd->query(), length))
+ {
+ thd->protocol->end_statement();
+ bootstrap_error= 1;
+ break;
+ }
+
mysql_parse(thd, thd->query(), length, &parser_state);
close_thread_tables(thd); // Free tables
@@ -1121,7 +1128,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#if defined(ENABLED_PROFILING)
thd->profiling.set_query_source(thd->query(), thd->query_length());
#endif
- Parser_state parser_state(thd, thd->query(), thd->query_length());
+ Parser_state parser_state;
+ if (parser_state.init(thd, thd->query(), thd->query_length()))
+ break;
mysql_parse(thd, thd->query(), thd->query_length(), &parser_state);
@@ -5907,14 +5916,17 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
bool error= 0;
DBUG_ENTER("mysql_test_parse_for_slave");
- Parser_state parser_state(thd, inBuf, length);
- lex_start(thd);
- mysql_reset_thd_for_next_command(thd);
+ Parser_state parser_state;
+ if (!(error= parser_state.init(thd, inBuf, length)))
+ {
+ lex_start(thd);
+ mysql_reset_thd_for_next_command(thd);
- if (!parse_sql(thd, & parser_state, NULL) &&
- all_tables_not_ok(thd, lex->select_lex.table_list.first))
- error= 1; /* Ignore question */
- thd->end_statement();
+ if (!parse_sql(thd, & parser_state, NULL) &&
+ all_tables_not_ok(thd, lex->select_lex.table_list.first))
+ error= 1; /* Ignore question */
+ thd->end_statement();
+ }
thd->cleanup_after_query();
DBUG_RETURN(error);
}
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index fa9c698622b..bc9a7d8ee65 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -4199,7 +4199,9 @@ bool mysql_unpack_partition(THD *thd,
thd->variables.character_set_client= system_charset_info;
- Parser_state parser_state(thd, part_buf, part_info_len);
+ Parser_state parser_state;
+ if (parser_state.init(thd, part_buf, part_info_len))
+ goto end;
if (init_lex_with_single_table(thd, table, &lex))
goto end;
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index f22cd448c32..b4cd57aeec0 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2944,7 +2944,9 @@ Execute_sql_statement::execute_server_code(THD *thd)
if (alloc_query(thd, m_sql_text.str, m_sql_text.length))
return TRUE;
- Parser_state parser_state(thd, thd->query(), thd->query_length());
+ Parser_state parser_state;
+ if (parser_state.init(thd, thd->query(), thd->query_length()))
+ return TRUE;
parser_state.m_lip.multi_statements= FALSE;
lex_start(thd);
@@ -3184,14 +3186,17 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
old_stmt_arena= thd->stmt_arena;
thd->stmt_arena= this;
- Parser_state parser_state(thd, thd->query(), thd->query_length());
- parser_state.m_lip.stmt_prepare_mode= TRUE;
- parser_state.m_lip.multi_statements= FALSE;
- lex_start(thd);
+ Parser_state parser_state;
+ if (!parser_state.init(thd, thd->query(), thd->query_length()))
+ {
+ parser_state.m_lip.stmt_prepare_mode= TRUE;
+ parser_state.m_lip.multi_statements= FALSE;
+ lex_start(thd);
- error= parse_sql(thd, & parser_state, NULL) ||
- thd->is_error() ||
- init_param_array(this);
+ error= parse_sql(thd, & parser_state, NULL) ||
+ thd->is_error() ||
+ init_param_array(this);
+ }
lex->set_trg_event_type_for_tables();
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index a71af6176b9..c3266b5cbe2 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -1327,9 +1327,9 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
thd->variables.sql_mode= (ulong)*trg_sql_mode;
- Parser_state parser_state(thd,
- trg_create_str->str,
- trg_create_str->length);
+ Parser_state parser_state;
+ if (parser_state.init(thd, trg_create_str->str, trg_create_str->length))
+ goto err_with_lex_cleanup;
Trigger_creation_ctx *creation_ctx=
Trigger_creation_ctx::create(thd,
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 3e47899d638..8cb4df36cd5 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1216,9 +1216,10 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
char old_db_buf[NAME_LEN+1];
LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) };
bool dbchanged;
- Parser_state parser_state(thd,
- table->select_stmt.str,
- table->select_stmt.length);
+ Parser_state parser_state;
+ if (parser_state.init(thd, table->select_stmt.str,
+ table->select_stmt.length))
+ goto err;
/*
Use view db name as thread default database, in order to ensure
diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc
index 7696f28081d..79a6fd79d4c 100644
--- a/sql/thr_malloc.cc
+++ b/sql/thr_malloc.cc
@@ -24,8 +24,6 @@
extern "C" {
void sql_alloc_error_handler(void)
{
- sql_print_error("%s", ER(ER_OUT_OF_RESOURCES));
-
THD *thd= current_thd;
if (thd)
{
@@ -53,6 +51,12 @@ extern "C" {
NULL);
}
}
+
+ /* Skip writing to the error log to avoid mtr complaints */
+ DBUG_EXECUTE_IF("simulate_out_of_memory", return;);
+
+ sql_print_error("%s", ER(ER_OUT_OF_RESOURCES));
+
}
}