List:Commits« Previous MessageNext Message »
From:kpettersson Date:October 30 2007 3:29pm
Subject:bk commit into 5.0 tree (thek:1.2536) BUG#31153
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of thek. When thek does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-10-30 15:29:30+01:00, thek@adventure.(none) +9 -0
  Bug #31153 calling stored procedure crashes server if available memory is low
  
  When the server was out of memory it crashed because of invalid memory access.
  
  This patch adds detection for failed memory allocations and make the server
  output a proper error message.

  mysys/my_new.cc@stripped, 2007-10-30 15:29:27+01:00, thek@adventure.(none) +3 -3
    Due to an inconsistency in gcc, the operator 'new' needs to be declared with an 
    empty throw() directive or it will not return a NULL pointer on a failed
    malloc call.

  sql/mysqld.cc@stripped, 2007-10-30 15:29:28+01:00, thek@adventure.(none) +1 -1
    Don't try to push_warning if there is no more memory. It will cause a
    recursion until the stack is consumed.

  sql/sp_head.cc@stripped, 2007-10-30 15:29:28+01:00, thek@adventure.(none) +44 -7
    Added check for out-of-memory on a 'new' operation.
    Refactored reset_lex method to return a error state code instead of void.
    Initialize the mem-root with init_sql_alloc to get a basic error handler for
    memory allocation problems. This alone won't prevent the server from crashing,
    NULL pointers have to be account for as well.

  sql/sp_head.h@stripped, 2007-10-30 15:29:28+01:00, thek@adventure.(none) +3 -3
    Due to an inconsistency in gcc, the operator 'new' needs to be declared with an 
    empty throw() directive or it will not return a NULL pointer on a failed
    malloc call.

  sql/sql_base.cc@stripped, 2007-10-30 15:29:28+01:00, thek@adventure.(none) +1 -2
    Use init_sql_alloc to get basic out-of-memory error handling.

  sql/sql_lex.h@stripped, 2007-10-30 15:29:28+01:00, thek@adventure.(none) +6 -0
    Overloaded new and delete operators for the sp_head class.

  sql/sql_parse.cc@stripped, 2007-10-30 15:29:28+01:00, thek@adventure.(none) +5 -2
    Removed assertion to be able to test fatal error recovery in debug mode.
    Added code to restore the net object associated with the recycled thd object
    so that it won't remember runtime settings from previous statements.

  sql/sql_prepare.cc@stripped, 2007-10-30 15:29:28+01:00, thek@adventure.(none) +1 -1
    Use init_sql_alloc to get basic out-of-memory error handling.

  sql/sql_yacc.yy@stripped, 2007-10-30 15:29:28+01:00, thek@adventure.(none) +31 -11
    If reset_lex fails, the parsing must stop to prevent access to uninitialized
    objects. The same goes for any memory allocation attempt.

diff -Nrup a/mysys/my_new.cc b/mysys/my_new.cc
--- a/mysys/my_new.cc	2006-12-23 20:04:08 +01:00
+++ b/mysys/my_new.cc	2007-10-30 15:29:27 +01:00
@@ -22,17 +22,17 @@
 
 #ifdef USE_MYSYS_NEW
 
-void *operator new (size_t sz)
+void *operator new (size_t sz) throw ()
 {
   return (void *) malloc (sz ? sz : 1);
 }
 
-void *operator new[] (size_t sz)
+void *operator new[] (size_t sz) throw ()
 {
   return (void *) malloc (sz ? sz : 1);
 }
 
-void operator delete (void *ptr)
+void operator delete (void *ptr) throw ()
 {
   if (ptr)
     free(ptr);
diff -Nrup a/sql/mysqld.cc b/sql/mysqld.cc
--- a/sql/mysqld.cc	2007-08-16 16:25:45 +02:00
+++ b/sql/mysqld.cc	2007-10-30 15:29:28 +01:00
@@ -2488,7 +2488,7 @@ static int my_message_sql(uint error, co
 
     thd->query_error=  1; // needed to catch query errors during replication
 
-    if (!thd->no_warnings_for_error)
+    if (!thd->no_warnings_for_error && error != ER_OUTOFMEMORY)
       push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str);
     /*
       thd->lex->current_select == 0 if lex structure is not inited
diff -Nrup a/sql/sp_head.cc b/sql/sp_head.cc
--- a/sql/sp_head.cc	2007-07-31 14:23:23 +02:00
+++ b/sql/sp_head.cc	2007-10-30 15:29:28 +01:00
@@ -411,14 +411,21 @@ check_routine_name(LEX_STRING ident)
  */
 
 void *
-sp_head::operator new(size_t size)
+sp_head::operator new(size_t size) throw()
 {
   DBUG_ENTER("sp_head::operator new");
   MEM_ROOT own_root;
   sp_head *sp;
 
-  init_alloc_root(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
+  init_sql_alloc(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
   sp= (sp_head *) alloc_root(&own_root, size);
+  if (sp == NULL)
+  {
+    THD *thd= current_thd;
+    my_error(ER_OUTOFMEMORY, MYF(0), size);
+    thd->fatal_error();
+    return NULL;
+  }
   sp->main_mem_root= own_root;
   DBUG_PRINT("info", ("mem_root 0x%lx", (ulong) &sp->mem_root));
   DBUG_RETURN(sp);
@@ -429,6 +436,10 @@ sp_head::operator delete(void *ptr, size
 {
   DBUG_ENTER("sp_head::operator delete");
   MEM_ROOT own_root;
+
+  if (ptr == NULL)
+    DBUG_VOID_RETURN;
+
   sp_head *sp= (sp_head *) ptr;
 
   /* Make a copy of main_mem_root as free_root will free the sp */
@@ -472,6 +483,14 @@ sp_head::init(LEX *lex)
 
   lex->spcont= m_pcont= new sp_pcontext();
 
+  if (!lex->spcont)
+  {
+    THD *thd= current_thd;
+    my_error(ER_OUTOFMEMORY,MYF(0), sizeof(sp_pcontext));
+    thd->fatal_error();
+    DBUG_VOID_RETURN;
+  }
+
   /*
     Altough trg_table_fields list is used only in triggers we init for all
     types of stored procedures to simplify reset_lex()/restore_lex() code.
@@ -973,7 +992,7 @@ sp_head::execute(THD *thd)
     DBUG_RETURN(TRUE);
 
   /* init per-instruction memroot */
-  init_alloc_root(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
+  init_sql_alloc(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
 
   DBUG_ASSERT(!(m_flags & IS_INVOKED));
   m_flags|= IS_INVOKED;
@@ -1795,16 +1814,33 @@ sp_head::execute_procedure(THD *thd, Lis
 }
 
 
-// Reset lex during parsing, before we parse a sub statement.
-void
+/**
+  @brief Reset lex during parsing, before we parse a sub statement.
+
+  @param thd Thread handler.
+
+  @return Error state
+    @retval true An error occurred.
+    @retval false Success.
+*/
+
+bool
 sp_head::reset_lex(THD *thd)
 {
   DBUG_ENTER("sp_head::reset_lex");
   LEX *sublex;
   LEX *oldlex= thd->lex;
 
+  sublex= new st_lex;
+  if (sublex == 0)
+  {
+    my_error(ER_OUTOFMEMORY, MYF(0),sizeof(st_lex));
+    thd->fatal_error();
+    DBUG_RETURN(TRUE);
+  }
+
+  thd->lex= sublex;
   (void)m_lex.push_front(oldlex);
-  thd->lex= sublex= new st_lex;
 
   /* Reset most stuff. */
   lex_start(thd);
@@ -1827,7 +1863,7 @@ sp_head::reset_lex(THD *thd)
   sublex->interval_list.empty();
   sublex->type= 0;
 
-  DBUG_VOID_RETURN;
+  DBUG_RETURN(FALSE);
 }
 
 // Restore lex during parsing, after we have parsed a sub statement.
@@ -3704,6 +3740,7 @@ sp_add_to_query_tables(THD *thd, LEX *le
   if (!(table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST))))
   {
     my_error(ER_OUTOFMEMORY, MYF(0), sizeof(TABLE_LIST));
+    thd->fatal_error();
     return NULL;
   }
   table->db_length= strlen(db);
diff -Nrup a/sql/sp_head.h b/sql/sp_head.h
--- a/sql/sp_head.h	2007-07-12 20:26:38 +02:00
+++ b/sql/sp_head.h	2007-10-30 15:29:28 +01:00
@@ -191,10 +191,10 @@ public:
   Security_context m_security_ctx;
 
   static void *
-  operator new(size_t size);
+  operator new(size_t size) throw ();
 
   static void
-  operator delete(void *ptr, size_t size);
+  operator delete(void *ptr, size_t size) throw ();
 
   sp_head();
 
@@ -254,7 +254,7 @@ public:
   }
 
   // Resets lex in 'thd' and keeps a copy of the old one.
-  void
+  bool
   reset_lex(THD *thd);
 
   // Restores lex in 'thd' from our copy, but keeps some status from the
diff -Nrup a/sql/sql_base.cc b/sql/sql_base.cc
--- a/sql/sql_base.cc	2007-08-24 13:28:10 +02:00
+++ b/sql/sql_base.cc	2007-10-30 15:29:28 +01:00
@@ -80,7 +80,6 @@ bool Prelock_error_handler::safely_trapp
   return ((m_handled_errors > 0) && (m_unhandled_errors == 0));
 }
 
-
 TABLE *unused_tables;				/* Used by mysql_test */
 HASH open_cache;				/* Used by mysql_test */
 
@@ -2643,7 +2642,7 @@ int open_tables(THD *thd, TABLE_LIST **s
     temporary mem_root for new .frm parsing.
     TODO: variables for size
   */
-  init_alloc_root(&new_frm_mem, 8024, 8024);
+  init_sql_alloc(&new_frm_mem, 8024, 8024);
 
   thd->current_tablenr= 0;
  restart:
diff -Nrup a/sql/sql_lex.h b/sql/sql_lex.h
--- a/sql/sql_lex.h	2007-08-28 17:51:02 +02:00
+++ b/sql/sql_lex.h	2007-10-30 15:29:28 +01:00
@@ -1169,6 +1169,11 @@ typedef struct st_lex : public Query_tab
 
   st_lex();
 
+  static void* 
+  operator new(size_t sz) throw() { return (void *) malloc (sz ? sz : 1); }
+
+  void operator delete (void *ptr) throw() { free(ptr); }
+
   virtual ~st_lex()
   {
     destroy_query_tables_list();
@@ -1303,3 +1308,4 @@ extern void lex_start(THD *thd);
 extern void lex_end(LEX *lex);
 extern int MYSQLlex(void *arg, void *yythd);
 extern char *skip_rear_comments(CHARSET_INFO *cs, char *begin, char *end);
+
diff -Nrup a/sql/sql_parse.cc b/sql/sql_parse.cc
--- a/sql/sql_parse.cc	2007-09-03 09:22:54 +02:00
+++ b/sql/sql_parse.cc	2007-10-30 15:29:28 +01:00
@@ -34,6 +34,7 @@
 #include "sp_cache.h"
 #include "sql_trigger.h"
 
+
 #ifdef HAVE_OPENSSL
 /*
   Without SSL the handshake consists of one packet. This packet
@@ -5850,6 +5851,7 @@ void mysql_reset_thd_for_next_command(TH
   DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
   thd->tmp_table_used= 0;
   thd->thread_specific_used= FALSE;
+
   if (!thd->in_sub_stmt)
   {
     if (opt_bin_log)
@@ -5862,6 +5864,9 @@ void mysql_reset_thd_for_next_command(TH
     thd->rand_used= 0;
     thd->sent_row_count= thd->examined_row_count= 0;
   }
+
+  thd->net.no_send_error= FALSE;
+  thd->net.no_send_ok= FALSE;
   DBUG_VOID_RETURN;
 }
 
@@ -6098,10 +6103,8 @@ void mysql_parse(THD *thd, const char *i
     }
     else
     {
-      DBUG_ASSERT(thd->net.report_error);
       DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
 			 thd->is_fatal_error));
-
       query_cache_abort(&thd->net);
     }
     if (thd->lex->sphead)
diff -Nrup a/sql/sql_prepare.cc b/sql/sql_prepare.cc
--- a/sql/sql_prepare.cc	2007-07-12 21:22:14 +02:00
+++ b/sql/sql_prepare.cc	2007-10-30 15:29:28 +01:00
@@ -2659,7 +2659,7 @@ Prepared_statement::Prepared_statement(T
   last_errno(0),
   flags((uint) IS_IN_USE)
 {
-  init_alloc_root(&main_mem_root, thd_arg->variables.query_alloc_block_size,
+  init_sql_alloc(&main_mem_root, thd_arg->variables.query_alloc_block_size,
                   thd_arg->variables.query_prealloc_size);
   *last_error= '\0';
 }
diff -Nrup a/sql/sql_yacc.yy b/sql/sql_yacc.yy
--- a/sql/sql_yacc.yy	2007-09-12 20:39:32 +02:00
+++ b/sql/sql_yacc.yy	2007-10-30 15:29:28 +01:00
@@ -1628,6 +1628,8 @@ create_function_tail:
 	    }
 	    /* Order is important here: new - reset - init */
 	    sp= new sp_head();
+            if (sp == NULL)
+              MYSQL_YYABORT;
 	    sp->reset_thd_mem_root(thd);
 	    sp->init(lex);
             sp->init_sp_name(thd, lex->spname);
@@ -1929,7 +1931,8 @@ sp_decl:
           {
             LEX *lex= Lex;
 
-            lex->sphead->reset_lex(YYTHD);
+            if (lex->sphead->reset_lex(YYTHD))
+              MYSQL_YYABORT;
             lex->spcont->declare_var_boundary($2);
           }
           type
@@ -1937,6 +1940,10 @@ sp_decl:
           {
             LEX *lex= Lex;
             sp_pcontext *pctx= lex->spcont;
+            if (pctx == 0)
+            {
+              MYSQL_YYABORT;
+            }
             uint num_vars= pctx->context_var_count();
             enum enum_field_types var_type= (enum enum_field_types) $4;
             Item *dflt_value_item= $5;
@@ -2064,7 +2071,8 @@ sp_decl:
 
 sp_cursor_stmt:
 	  {
-	    Lex->sphead->reset_lex(YYTHD);
+	    if(Lex->sphead->reset_lex(YYTHD))
+              MYSQL_YYABORT;
 
 	    /* We use statement here just be able to get a better
 	       error message. Using 'select' works too, but will then
@@ -2230,7 +2238,8 @@ sp_proc_stmt:
 	    LEX *lex= thd->lex;
             Lex_input_stream *lip= thd->m_lip;
 
-	    lex->sphead->reset_lex(thd);
+	    if (lex->sphead->reset_lex(thd))
+              MYSQL_YYABORT;
 	    lex->sphead->m_tmp_query= lip->tok_start;
 	  }
 	  statement
@@ -2275,7 +2284,7 @@ sp_proc_stmt:
 	    sp->restore_lex(thd);
           }
           | RETURN_SYM 
-          { Lex->sphead->reset_lex(YYTHD); }
+          { if(Lex->sphead->reset_lex(YYTHD)) MYSQL_YYABORT; }
           expr
 	  {
 	    LEX *lex= Lex;
@@ -2472,7 +2481,7 @@ sp_fetch_list:
 	;
 
 sp_if:
-          { Lex->sphead->reset_lex(YYTHD); }
+          { if (Lex->sphead->reset_lex(YYTHD)) MYSQL_YYABORT; }
           expr THEN_SYM
 	  {
 	    LEX *lex= Lex;
@@ -2522,7 +2531,7 @@ simple_case_stmt:
           {
             LEX *lex= Lex;
             case_stmt_action_case(lex);
-            lex->sphead->reset_lex(YYTHD); /* For expr $3 */
+            if (lex->sphead->reset_lex(YYTHD)) MYSQL_YYABORT; /* For expr $3 */
           }
           expr
           {
@@ -2571,7 +2580,7 @@ searched_when_clause_list:
 simple_when_clause:
           WHEN_SYM
           {
-            Lex->sphead->reset_lex(YYTHD); /* For expr $3 */
+            if (Lex->sphead->reset_lex(YYTHD)) MYSQL_YYABORT; /* For expr $3 */
           }
           expr
           {
@@ -2592,7 +2601,7 @@ simple_when_clause:
 searched_when_clause:
           WHEN_SYM
           {
-            Lex->sphead->reset_lex(YYTHD); /* For expr $3 */
+            if (Lex->sphead->reset_lex(YYTHD)) MYSQL_YYABORT; /* For expr $3 */
           }
           expr
           {
@@ -2703,7 +2712,7 @@ sp_unlabeled_control:
 	    lex->sphead->add_instr(i);
 	  }
         | WHILE_SYM 
-          { Lex->sphead->reset_lex(YYTHD); }
+          { if (Lex->sphead->reset_lex(YYTHD)) MYSQL_YYABORT; }
           expr DO_SYM
 	  {
 	    LEX *lex= Lex;
@@ -2729,7 +2738,7 @@ sp_unlabeled_control:
             lex->sphead->do_cont_backpatch();
 	  }
         | REPEAT_SYM sp_proc_stmts1 UNTIL_SYM 
-          { Lex->sphead->reset_lex(YYTHD); }
+          { if (Lex->sphead->reset_lex(YYTHD)) MYSQL_YYABORT; }
           expr END REPEAT_SYM
 	  {
 	    LEX *lex= Lex;
@@ -4271,6 +4280,8 @@ select_init2:
 	select_part2
         {
 	  LEX *lex= Lex;
+          if (lex == NULL)
+            MYSQL_YYABORT;
           SELECT_LEX * sel= lex->current_select;
           if (lex->current_select->set_braces(0))
 	  {
@@ -8422,7 +8433,14 @@ option_type_value:
 
               QQ: May be we should simply prohibit group assignments in SP?
             */
-            Lex->sphead->reset_lex(thd);
+            if (Lex->sphead->reset_lex(thd))
+            {
+              /*
+                Failed to allocate memory or something else really bad
+                happened.
+              */
+              MYSQL_YYABORT;
+            }
             lex= thd->lex;
 
             /* Set new LEX as if we at start of set rule. */
@@ -9832,6 +9850,8 @@ sp_tail:
 
 	  /* Order is important here: new - reset - init */
 	  sp= new sp_head();
+          if (sp == NULL)
+            MYSQL_YYABORT;
 	  sp->reset_thd_mem_root(YYTHD);
 	  sp->init(lex);
 	  sp->m_type= TYPE_ENUM_PROCEDURE;
Thread
bk commit into 5.0 tree (thek:1.2536) BUG#31153kpettersson30 Oct
  • Re: bk commit into 5.0 tree (thek:1.2536) BUG#31153Marc Alff14 Nov
  • Re: bk commit into 5.0 tree (thek:1.2536) BUG#31153Konstantin Osipov19 Nov