List:Commits« Previous MessageNext Message »
From:Marc Alff Date:August 8 2008 7:00pm
Subject:bzr commit into mysql-5.0 branch (marc.alff:2656) Bug#38296
View as plain text  
#At file:///home/malff/BZR-TREE/mysql-5.0-38296/

 2656 Marc Alff	2008-08-08
      Bug#38296 (low memory crash with many conditions in a query)
      
      This fix is for 5.0/5.1 only
      
      Before this fix, a query using many an arbitrary number of conditions in a
      query could consume arbitrary amount of memory in the server, and cause
      a crash in the parser on Out Of Memory condition, due to an optimization
      implemented for OR / XOR / AND operators.
      
      With this fix, the parser now gracefully returns an ER_OUT_OF_RESOURCES
      error to the client when OOM occurs when parsing OR / XOR / AND.
      
      No test scripts are provided, since automating OOM failures is not
      instrumented in the server.
      Tested under the debugger, to verify that an error in alloc_root cause the
      thread to returns gracefully all the way to the client application, with
      an ER_OUT_OF_RESOURCES error.
modified:
  mysys/my_alloc.c
  sql/field.h
  sql/item.h
  sql/sp_head.cc
  sql/sql_lex.h
  sql/sql_list.h
  sql/sql_string.h
  sql/sql_yacc.yy
  sql/thr_malloc.cc

=== modified file 'mysys/my_alloc.c'
--- a/mysys/my_alloc.c	2007-04-18 20:50:32 +0000
+++ b/mysys/my_alloc.c	2008-08-08 16:59:58 +0000
@@ -202,7 +202,7 @@ gptr alloc_root(MEM_ROOT *mem_root,unsig
     {
       if (mem_root->error_handler)
 	(*mem_root->error_handler)();
-      return((gptr) 0);				/* purecov: inspected */
+      DBUG_RETURN((gptr) 0);			/* purecov: inspected */
     }
     mem_root->block_num++;
     next->next= *prev;

=== modified file 'sql/field.h'
--- a/sql/field.h	2008-05-06 16:43:46 +0000
+++ b/sql/field.h	2008-08-08 16:59:58 +0000
@@ -48,7 +48,8 @@ class Field
   Field(const Item &);				/* Prevent use of these */
   void operator=(Field &);
 public:
-  static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
+  static void *operator new(size_t size) throw ()
+  { return (void*) sql_alloc((uint) size); }
   static void operator delete(void *ptr_arg, size_t size) { TRASH(ptr_arg, size); }
 
   char		*ptr;			// Position to field in record

=== modified file 'sql/item.h'
--- a/sql/item.h	2008-03-12 07:59:15 +0000
+++ b/sql/item.h	2008-08-08 16:59:58 +0000
@@ -439,9 +439,9 @@ class Item {
   Item(const Item &);			/* Prevent use of these */
   void operator=(Item &);
 public:
-  static void *operator new(size_t size)
+  static void *operator new(size_t size) throw ()
   { return (void*) sql_alloc((uint) size); }
-  static void *operator new(size_t size, MEM_ROOT *mem_root)
+  static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
   { return (void*) alloc_root(mem_root, (uint) size); }
   static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
   static void operator delete(void *ptr, MEM_ROOT *mem_root) {}

=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	2008-07-14 21:41:30 +0000
+++ b/sql/sp_head.cc	2008-08-08 16:59:58 +0000
@@ -446,7 +446,7 @@ sp_head::operator new(size_t size) throw
   init_sql_alloc(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
   sp= (sp_head *) alloc_root(&own_root, size);
   if (sp == NULL)
-    return NULL;
+    DBUG_RETURN(NULL);
   sp->main_mem_root= own_root;
   DBUG_PRINT("info", ("mem_root 0x%lx", (ulong) &sp->mem_root));
   DBUG_RETURN(sp);

=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h	2008-07-14 21:41:30 +0000
+++ b/sql/sql_lex.h	2008-08-08 16:59:58 +0000
@@ -331,11 +331,11 @@ public:
   bool no_table_names_allowed; /* used for global order by */
   bool no_error; /* suppress error message (convert it to warnings) */
 
-  static void *operator new(size_t size)
+  static void *operator new(size_t size) throw ()
   {
     return (void*) sql_alloc((uint) size);
   }
-  static void *operator new(size_t size, MEM_ROOT *mem_root)
+  static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
   { return (void*) alloc_root(mem_root, (uint) size); }
   static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
   static void operator delete(void *ptr, MEM_ROOT *mem_root) {}

=== modified file 'sql/sql_list.h'
--- a/sql/sql_list.h	2007-03-29 06:35:28 +0000
+++ b/sql/sql_list.h	2008-08-08 16:59:58 +0000
@@ -27,7 +27,7 @@ public:
   {
     return (void*) sql_alloc((uint) size);
   }
-  static void *operator new[](size_t size)
+  static void *operator new[](size_t size) throw ()
   {
     return (void*) sql_alloc((uint) size);
   }
@@ -466,7 +466,7 @@ public:
 struct ilink
 {
   struct ilink **prev,*next;
-  static void *operator new(size_t size)
+  static void *operator new(size_t size) throw ()
   {
     return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE));
   }

=== modified file 'sql/sql_string.h'
--- a/sql/sql_string.h	2007-01-22 12:10:46 +0000
+++ b/sql/sql_string.h	2008-08-08 16:59:58 +0000
@@ -78,7 +78,7 @@ public:
     Alloced_length=str.Alloced_length; alloced=0; 
     str_charset=str.str_charset;
   }
-  static void *operator new(size_t size, MEM_ROOT *mem_root)
+  static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
   { return (void*) alloc_root(mem_root, (uint) size); }
   static void operator delete(void *ptr_arg,size_t size)
   { TRASH(ptr_arg, size); }

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2008-07-14 21:41:30 +0000
+++ b/sql/sql_yacc.yy	2008-08-08 16:59:58 +0000
@@ -4577,12 +4577,16 @@ expr:
             {
               /* X OR Y */
               $$ = new (YYTHD->mem_root) Item_cond_or($1, $3);
+              if ($$ == NULL)
+                MYSQL_YYABORT;
             }
           }
         | expr XOR expr %prec XOR
           {
             /* XOR is a proprietary extension */
             $$ = new (YYTHD->mem_root) Item_cond_xor($1, $3);
+            if ($$ == NULL)
+              MYSQL_YYABORT;
           }
         | expr and expr %prec AND_SYM
           {
@@ -4623,6 +4627,8 @@ expr:
             {
               /* X AND Y */
               $$ = new (YYTHD->mem_root) Item_cond_and($1, $3);
+              if ($$ == NULL)
+                MYSQL_YYABORT;
             }
           }
 	| NOT_SYM expr %prec NOT_SYM

=== modified file 'sql/thr_malloc.cc'
--- a/sql/thr_malloc.cc	2006-12-31 00:02:27 +0000
+++ b/sql/thr_malloc.cc	2008-08-08 16:59:58 +0000
@@ -21,10 +21,35 @@
 extern "C" {
   void sql_alloc_error_handler(void)
   {
-    THD *thd=current_thd;
-    if (thd)					// QQ;  To be removed
-      thd->fatal_error();			/* purecov: inspected */
     sql_print_error(ER(ER_OUT_OF_RESOURCES));
+
+    THD *thd=current_thd;
+    if (thd)
+    {
+      /*
+        This thread is Out Of Memory.
+        An OOM condition is a fatal error.
+        It should not be caught by error handlers in stored procedures.
+        Also, recording that SQL condition in the condition area could
+        cause more memory allocations, which in turn could raise more
+        OOM conditions, causing recursion in the error handling code itself.
+        As a result, my_error() should not be invoked, and the
+        thread diagnostics area is set to an error status directly.
+        The visible result for a client application will be:
+        - a query fails with an ER_OUT_OF_RESOURCES error,
+        returned in the error packet.
+        - SHOW ERROR/SHOW WARNINGS may be empty.
+      */
+
+      NET *net= &thd->net;
+      thd->fatal_error();
+      if (!net->last_error[0])                  // Return only first message
+      {
+        strmake(net->last_error, ER(ER_OUT_OF_RESOURCES),
+                sizeof(net->last_error)-1);
+        net->last_errno= ER_OUT_OF_RESOURCES;
+      }
+    }
   }
 }
 

Thread
bzr commit into mysql-5.0 branch (marc.alff:2656) Bug#38296Marc Alff8 Aug