diff options
author | Alexey Kopytov <Alexey.Kopytov@Sun.com> | 2010-06-11 17:48:24 +0400 |
---|---|---|
committer | Alexey Kopytov <Alexey.Kopytov@Sun.com> | 2010-06-11 17:48:24 +0400 |
commit | f84b3f5c21c62ebe3b489250a09aca0ffde1313c (patch) | |
tree | bad36a3866fc1f57ed09d6de5a590fa2e12bacfe | |
parent | 26a034959299cb72d04d92ab330dfb83ef6082a6 (diff) | |
parent | e5cf56ef80391caca2f06b34fc1de1313196e91f (diff) | |
download | mariadb-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.result | 9 | ||||
-rw-r--r-- | mysql-test/t/error_simulation.test | 14 | ||||
-rw-r--r-- | mysys/my_alloc.c | 16 | ||||
-rw-r--r-- | mysys/my_malloc.c | 12 | ||||
-rw-r--r-- | mysys/safemalloc.c | 7 | ||||
-rw-r--r-- | sql/event_data_objects.cc | 5 | ||||
-rw-r--r-- | sql/log_event.cc | 9 | ||||
-rw-r--r-- | sql/mysqld.cc | 4 | ||||
-rw-r--r-- | sql/sp.cc | 9 | ||||
-rw-r--r-- | sql/sql_class.cc | 3 | ||||
-rw-r--r-- | sql/sql_lex.cc | 30 | ||||
-rw-r--r-- | sql/sql_lex.h | 32 | ||||
-rw-r--r-- | sql/sql_parse.cc | 30 | ||||
-rw-r--r-- | sql/sql_partition.cc | 4 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 21 | ||||
-rw-r--r-- | sql/sql_trigger.cc | 6 | ||||
-rw-r--r-- | sql/sql_view.cc | 7 | ||||
-rw-r--r-- | sql/thr_malloc.cc | 8 |
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)); + } } |