List:Commits« Previous MessageNext Message »
From:kpettersson Date:October 18 2007 8:15am
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-18 10:15:10+02: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 detects the failed memory allocation and have the server output a
  proper error message.

  mysys/my_new.cc@stripped, 2007-10-18 10:15:07+02: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-18 10:15:07+02:00, thek@adventure.(none) +1 -1
    Changed my_message_sql to have global scope so that error message handle can
    be restored after a fatal error message.

  sql/sp_head.cc@stripped, 2007-10-18 10:15:07+02:00, thek@adventure.(none) +41 -5
    Added check for out-of-memory on a 'new' operation.
    Refactored reset_lex method to return a error state code instead of void.

  sql/sp_head.h@stripped, 2007-10-18 10:15:07+02: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_class.cc@stripped, 2007-10-18 10:15:07+02:00, thek@adventure.(none) +1 -0
    Make a small attempt to recover from fatal error.

  sql/sql_class.h@stripped, 2007-10-18 10:15:07+02:00, thek@adventure.(none) +1 -0
    Set error handler to 'fatal_error_handler_hook' to avoid a situation where 
    an out-of-memory error message can't be displayed because of out-of-memory error.

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

  sql/sql_parse.cc@stripped, 2007-10-18 10:15:07+02:00, thek@adventure.(none) +9 -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.
    Happily violated the visibility principle of the global variable 
    error_handler_hook.

  sql/sql_yacc.yy@stripped, 2007-10-18 10:15:08+02:00, thek@adventure.(none) +27 -11
    If reset_lex fails, the parsing must stop to prevent access to uninitialized
    objects.

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-18 10:15:07 +02: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-18 10:15:07 +02:00
@@ -2460,7 +2460,7 @@ static void check_data_home(const char *
 
 
 /* ARGSUSED */
-static int my_message_sql(uint error, const char *str, myf MyFlags)
+int my_message_sql(uint error, const char *str, myf MyFlags)
 {
   THD *thd;
   DBUG_ENTER("my_message_sql");
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-18 10:15:07 +02:00
@@ -411,7 +411,7 @@ 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;
@@ -419,6 +419,13 @@ sp_head::operator new(size_t size)
 
   init_alloc_root(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
   sp= (sp_head *) alloc_root(&own_root, size);
+  if (sp == NULL)
+  {
+    THD *thd= current_thd;
+    thd->fatal_error();
+    my_error(ER_OUTOFMEMORY, MYF(0));
+    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;
+    current_thd->fatal_error();
+    my_error(ER_OUTOFMEMORY,MYF(0));
+    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.
@@ -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)
+  {
+    thd->fatal_error();
+    my_error(ER_OUTOFMEMORY, MYF(0));
+    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.
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-18 10:15:07 +02: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_class.cc b/sql/sql_class.cc
--- a/sql/sql_class.cc	2007-08-02 02:39:10 +02:00
+++ b/sql/sql_class.cc	2007-10-18 10:15:07 +02:00
@@ -639,6 +639,7 @@ void THD::cleanup_after_query()
   free_items();
   /* Reset where. */
   where= THD::DEFAULT_WHERE;
+
 }
 
 
diff -Nrup a/sql/sql_class.h b/sql/sql_class.h
--- a/sql/sql_class.h	2007-08-02 02:39:10 +02:00
+++ b/sql/sql_class.h	2007-10-18 10:15:07 +02:00
@@ -1699,6 +1699,7 @@ public:
 #endif
   inline void fatal_error()
   {
+    error_handler_hook=fatal_error_handler_hook;
     is_fatal_error= 1;
     net.report_error= 1;
     DBUG_PRINT("error",("Fatal error set"));
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-18 10:15:07 +02: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-18 10:15:07 +02:00
@@ -21,6 +21,8 @@
 #include <myisam.h>
 #include <my_dir.h>
 
+extern int my_message_sql(uint error, const char *str, myf MyFlags);
+
 #ifdef HAVE_INNOBASE_DB
 #include "ha_innodb.h"
 #endif
@@ -34,6 +36,7 @@
 #include "sp_cache.h"
 #include "sql_trigger.h"
 
+
 #ifdef HAVE_OPENSSL
 /*
   Without SSL the handshake consists of one packet. This packet
@@ -5850,6 +5853,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 +5866,11 @@ 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;
+  error_handler_hook= my_message_sql;
   DBUG_VOID_RETURN;
 }
 
@@ -6098,10 +6107,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_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-18 10:15:08 +02:00
@@ -1929,7 +1929,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 +1938,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 +2069,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 +2236,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 +2282,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 +2479,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 +2529,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 +2578,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 +2599,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 +2710,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 +2736,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 +4278,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 +8431,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. */
Thread
bk commit into 5.0 tree (thek:1.2536) BUG#31153kpettersson18 Oct