List:Commits« Previous MessageNext Message »
From:Alexey Kopytov Date:May 20 2010 10:37am
Subject:bzr commit into mysql-5.1-bugteam branch (Alexey.Kopytov:3387)
Bug#42064
View as plain text  
#At file:///data/src/bzr/bugteam/bug42064/my51-bug42064/ based on revid:sergey.glukhov@stripped

 3387 Alexey Kopytov	2010-05-20
      Bug #42064: low memory crash when importing hex strings, in
                  Item_hex_string::Item_hex_string
      
      The status of memory allocation in the Lex_input_stream (called
      from the Parser_state constructor) was not checked which led to
      a parser crash in case of the out-of-memory error.
      
      The solution is to check thd->is_error() since this is the only
      way we can handle memory allocation errors occuring in
      constructors.
     @ mysql-test/r/error_simulation.result
        Added a test case for bug #42064.
     @ mysql-test/t/error_simulation.test
        Added a test case for bug #42064.
     @ mysys/my_alloc.c
        Added error injection code for the regression test.
     @ mysys/my_malloc.c
        Added error injection code for the regression test.
     @ mysys/safemalloc.c
        Added error injection code for the regression test.
     @ sql/event_data_objects.cc
        Check thd->is_error() to handle memory allocation errors after
        calling the Parser_state constructor.
     @ sql/sp.cc
        Check thd->is_error() to handle memory allocation errors after
        calling the Parser_state constructor.
     @ sql/sql_lex.cc
        Added error injection code for the regression test.
     @ sql/sql_parse.cc
        Check thd->is_error() to handle memory allocation errors after
        calling the Parser_state constructor.
     @ sql/sql_partition.cc
        Check thd->is_error() to handle memory allocation errors after
        calling the Parser_state constructor.
     @ sql/sql_prepare.cc
        Check thd->is_error() to handle memory allocation errors after
        calling the Parser_state constructor.
     @ sql/sql_trigger.cc
        Check thd->is_error() to handle memory allocation errors after
        calling the Parser_state constructor.
     @ sql/sql_view.cc
        Check thd->is_error() to handle memory allocation errors after
        calling the Parser_state constructor.
     @ sql/thr_malloc.cc
        Added error injection code for the regression test.

    modified:
      mysql-test/r/error_simulation.result
      mysql-test/t/error_simulation.test
      mysys/my_alloc.c
      mysys/my_malloc.c
      mysys/safemalloc.c
      sql/event_data_objects.cc
      sql/sp.cc
      sql/sql_lex.cc
      sql/sql_parse.cc
      sql/sql_partition.cc
      sql/sql_prepare.cc
      sql/sql_trigger.cc
      sql/sql_view.cc
      sql/thr_malloc.cc
=== modified file 'mysql-test/r/error_simulation.result'
--- a/mysql-test/r/error_simulation.result	2010-04-25 11:06:40 +0000
+++ b/mysql-test/r/error_simulation.result	2010-05-20 10:36:56 +0000
@@ -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("");
+ERROR HY000: Out of memory; check if mysqld or some other process uses all available memory; if not, you may have to use 'ulimit' to allow mysqld to use more memory or you can add more swap space
+SET SESSION debug=DEFAULT;
+DROP TABLE t1;
+#
 # End of 5.1 tests
 #

=== modified file 'mysql-test/t/error_simulation.test'
--- a/mysql-test/t/error_simulation.test	2010-04-25 11:06:40 +0000
+++ b/mysql-test/t/error_simulation.test	2010-05-20 10:36:56 +0000
@@ -47,5 +47,18 @@ 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";
+--error ER_OUT_OF_RESOURCES
+INSERT INTO t1 VALUES("");
+SET SESSION debug=DEFAULT;
+
+DROP TABLE t1;
+
+--echo #
 --echo # End of 5.1 tests
 --echo #

=== modified file 'mysys/my_alloc.c'
--- a/mysys/my_alloc.c	2009-01-15 18:11:25 +0000
+++ b/mysys/my_alloc.c	2010-05-20 10:36:56 +0000
@@ -176,6 +176,14 @@ void *alloc_root(MEM_ROOT *mem_root, siz
   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)
   {

=== modified file 'mysys/my_malloc.c'
--- a/mysys/my_malloc.c	2007-10-02 07:32:33 +0000
+++ b/mysys/my_malloc.c	2010-05-20 10:36:56 +0000
@@ -31,13 +31,23 @@ void *my_malloc(size_t size, myf my_flag
 
   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);
   }

=== modified file 'mysys/safemalloc.c'
--- a/mysys/safemalloc.c	2009-05-15 07:53:50 +0000
+++ b/mysys/safemalloc.c	2010-05-20 10:36:56 +0000
@@ -139,6 +139,11 @@ void *_mymalloc(size_t size, const char 
 				     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 
     }
     DBUG_PRINT("error",("Out of memory, in use: %ld at line %d, '%s'",
 			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);

=== modified file 'sql/event_data_objects.cc'
--- a/sql/event_data_objects.cc	2010-01-19 09:03:40 +0000
+++ b/sql/event_data_objects.cc	2010-05-20 10:36:56 +0000
@@ -1434,6 +1434,14 @@ Event_job_data::execute(THD *thd, bool d
 
   {
     Parser_state parser_state(thd, thd->query(), thd->query_length());
+    /*
+      Since the Parser_state constructor may try to allocate large amounts of
+      memory (indirectly, via Lex_input_stream constructor), check
+      thd->is_error() to handle the out-of-memory error.
+    */
+    if (thd->is_error())
+      goto end;
+
     lex_start(thd);
 
     if (parse_sql(thd, & parser_state, creation_ctx))

=== modified file 'sql/sp.cc'
--- a/sql/sp.cc	2010-02-05 09:39:46 +0000
+++ b/sql/sp.cc	2010-05-20 10:36:56 +0000
@@ -783,6 +783,16 @@ db_load_routine(THD *thd, int type, sp_n
 
   {
     Parser_state parser_state(thd, defstr.c_ptr(), defstr.length());
+    /*
+      Since the Parser_state constructor may try to allocate large amounts of
+      memory (indirectly, via Lex_input_stream constructor), check
+      thd->is_error() to handle the out-of-memory error.
+    */
+    if (thd->is_error())
+    {
+      ret= SP_INTERNAL_ERROR;
+      goto end;
+    }
 
     lex_start(thd);
 

=== modified file 'sql/sql_lex.cc'
--- a/sql/sql_lex.cc	2010-04-01 13:15:22 +0000
+++ b/sql/sql_lex.cc	2010-05-20 10:36:56 +0000
@@ -137,7 +137,11 @@ Lex_input_stream::Lex_input_stream(THD *
   in_comment(NO_COMMENT),
   m_underscore_cs(NULL)
 {
+  DBUG_EXECUTE_IF("bug42064_simulate_oom",
+                  DBUG_SET("+d,simulate_out_of_memory"););
   m_cpp_buf= (char*) thd->alloc(length + 1);
+  DBUG_EXECUTE_IF("bug42064_simulate_oom",
+                  DBUG_SET("-d,bug42064_simulate_oom"););
   m_cpp_ptr= m_cpp_buf;
 }
 

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-05-11 14:39:51 +0000
+++ b/sql/sql_parse.cc	2010-05-20 10:36:56 +0000
@@ -5945,9 +5945,19 @@ void mysql_parse(THD *thd, const char *i
     sp_cache_flush_obsolete(&thd->sp_func_cache);
 
     Parser_state parser_state(thd, inBuf, length);
-
-    bool err= parse_sql(thd, & parser_state, NULL);
-    *found_semicolon= parser_state.m_lip.found_semicolon;
+    bool err;
+    /*
+      Since the Parser_state constructor may try to allocate large amounts of
+      memory (indirectly, via Lex_input_stream constructor), check
+      thd->is_error() to handle the out-of-memory error.
+    */
+    if (!(err= thd->is_error()))
+    {
+      err= parse_sql(thd, & parser_state, NULL);
+      *found_semicolon= parser_state.m_lip.found_semicolon;
+    }
+    else
+      *found_semicolon= NULL;
 
     if (!err)
     {
@@ -6034,12 +6044,20 @@ bool mysql_test_parse_for_slave(THD *thd
   DBUG_ENTER("mysql_test_parse_for_slave");
 
   Parser_state parser_state(thd, inBuf, length);
-  lex_start(thd);
-  mysql_reset_thd_for_next_command(thd);
+  /*
+    Since the Parser_state constructor may try to allocate large amounts of
+    memory (indirectly, via Lex_input_stream constructor), check
+    thd->is_error() to handle the out-of-memory error.
+  */
+  if (!thd->is_error())
+  {
+    lex_start(thd);
+    mysql_reset_thd_for_next_command(thd);
 
-  if (!parse_sql(thd, & parser_state, NULL) &&
-      all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
-    error= 1;                  /* Ignore question */
+    if (!parse_sql(thd, & parser_state, NULL) &&
+        all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
+      error= 1;                  /* Ignore question */
+  }
   thd->end_statement();
   thd->cleanup_after_query();
   DBUG_RETURN(error);

=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc	2010-05-04 12:26:44 +0000
+++ b/sql/sql_partition.cc	2010-05-20 10:36:56 +0000
@@ -3893,6 +3893,13 @@ bool mysql_unpack_partition(THD *thd,
   thd->variables.character_set_client= system_charset_info;
 
   Parser_state parser_state(thd, part_buf, part_info_len);
+  /*
+    Since the Parser_state constructor may try to allocate large amounts of
+    memory (indirectly, via Lex_input_stream constructor), check
+    thd->is_error() to catch the out-of-memory error.
+  */
+  if (thd->is_error())
+    goto end;
 
   lex_start(thd);
   *work_part_info_used= false;

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	2010-01-16 07:44:24 +0000
+++ b/sql/sql_prepare.cc	2010-05-20 10:36:56 +0000
@@ -3035,12 +3035,20 @@ bool Prepared_statement::prepare(const c
   thd->stmt_arena= this;
 
   Parser_state parser_state(thd, thd->query(), thd->query_length());
-  parser_state.m_lip.stmt_prepare_mode= TRUE;
-  lex_start(thd);
-
-  error= parse_sql(thd, & parser_state, NULL) ||
-         thd->is_error() ||
-         init_param_array(this);
+  /*
+    Since the Parser_state constructor may try to allocate large amounts of
+    memory (indirectly, via Lex_input_stream constructor), check
+    thd->is_error() to handle the out-of-memory error.
+  */
+  if (!(error= thd->is_error()))
+  {
+    parser_state.m_lip.stmt_prepare_mode= TRUE;
+    lex_start(thd);
+
+    error= parse_sql(thd, & parser_state, NULL) ||
+      thd->is_error() ||
+      init_param_array(this);
+  }
 
   lex->set_trg_event_type_for_tables();
 

=== modified file 'sql/sql_trigger.cc'
--- a/sql/sql_trigger.cc	2010-01-28 14:41:14 +0000
+++ b/sql/sql_trigger.cc	2010-05-20 10:36:56 +0000
@@ -1300,6 +1300,13 @@ bool Table_triggers_list::check_n_load(T
         Parser_state parser_state(thd,
                                   trg_create_str->str,
                                   trg_create_str->length);
+        /*
+          Since the Parser_state constructor may try to allocate large amounts
+          of memory (indirectly, via Lex_input_stream constructor), check
+          thd->is_error() to handle the out-of-memory error.
+        */
+        if (thd->is_error())
+          goto err_with_lex_cleanup;
 
         Trigger_creation_ctx *creation_ctx=
           Trigger_creation_ctx::create(thd,

=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc	2010-03-09 10:36:26 +0000
+++ b/sql/sql_view.cc	2010-05-20 10:36:56 +0000
@@ -1193,6 +1193,13 @@ bool mysql_make_view(THD *thd, File_pars
     Parser_state parser_state(thd,
                               table->select_stmt.str,
                               table->select_stmt.length);
+    /*
+      Since the Parser_state constructor may try to allocate large amounts of
+      memory (indirectly, via Lex_input_stream constructor), check
+      thd->is_error() to handle the out-of-memory error.
+    */
+    if (thd->is_error())
+      goto err;
 
     /* 
       Use view db name as thread default database, in order to ensure

=== modified file 'sql/thr_malloc.cc'
--- a/sql/thr_malloc.cc	2009-06-29 14:00:47 +0000
+++ b/sql/thr_malloc.cc	2010-05-20 10:36:56 +0000
@@ -21,8 +21,6 @@
 extern "C" {
   void sql_alloc_error_handler(void)
   {
-    sql_print_error("%s", ER(ER_OUT_OF_RESOURCES));
-
     THD *thd= current_thd;
     if (thd)
     {
@@ -49,6 +47,12 @@ extern "C" {
                                       ER(ER_OUT_OF_RESOURCES));
       }
     }
+
+    /* Skip writing to the error log to avoid mtr complains */
+    DBUG_EXECUTE_IF("simulate_out_of_memory", return;);
+
+    sql_print_error("%s", ER(ER_OUT_OF_RESOURCES));
+
   }
 }
 


Attachment: [text/bzr-bundle] bzr/alexey.kopytov@sun.com-20100520103656-dxfk3192zkcqju9y.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (Alexey.Kopytov:3387)Bug#42064Alexey Kopytov20 May