List:Commits« Previous MessageNext Message »
From:Gleb Shchepa Date:April 1 2009 9:49pm
Subject:bzr commit into mysql-5.0-bugteam branch (gshchepa:2722) Bug#37362
View as plain text  
#At file:///work/bzr/5.0-37362/ based on revid:gshchepa@stripped

 2722 Gleb Shchepa	2009-04-02
      Bug #37362: Crash in do_field_eq
      
      EXPLAIN EXTENDED of nested query containing a error:
      
         1054 Unknown column '...' in 'field list'
         
      may cause a server crash.
      
      
      Parse error like described above forces a call to
      JOIN::destroy() on malformed subquery.
      That JOIN::destroy function closes and frees temporary
      tables. However, temporary fields of these tables
      may be listed in st_select_lex::group_list of outer
      query, and that st_select_lex may not cleanup them
      properly. So, after the JOIN::destroy call that
      st_select_lex::group_list may have Item_field
      objects with dangling pointers to freed temporary
      table Field objects. That caused a crash.
      
      To prevent dangling pointers,
      1) a list of temporary table fields has been added
      to JOIN class;
      2) JOIN::destroy has been modified to cleanup
      temporary table fields.
      modified:
        mysql-test/r/subselect3.result
        mysql-test/t/subselect3.test
        sql/sql_select.cc
        sql/sql_select.h

per-file messages:
  mysql-test/r/subselect3.result
    Added test case for bug #37362.
  mysql-test/t/subselect3.test
    Added test case for bug #37362.
  sql/sql_select.cc
    Bug #37362: Crash in do_field_eq
    
    1) JOIN::destroy() has been modified to
    cleanup temporary table field items;
    2) setup_copy_fields() has been modified to
    collect these items.
  sql/sql_select.h
    Bug #37362: Crash in do_field_eq
    
    1) JOIN::tmp_table_field_list has been added to
    collect newly created temporary table field items.
    2) setup_copy_fields function: extra output parameter
    has been added to pass that item list.
=== modified file 'mysql-test/r/subselect3.result'
--- a/mysql-test/r/subselect3.result	2009-01-28 18:46:45 +0000
+++ b/mysql-test/r/subselect3.result	2009-04-01 21:49:18 +0000
@@ -849,4 +849,23 @@ ROW(1,2) = (SELECT    1,    1)	ROW(1,2) 
 SELECT ROW(1,2) = (SELECT    1,    2), ROW(1,2) IN (SELECT    1,    2);
 ROW(1,2) = (SELECT    1,    2)	ROW(1,2) IN (SELECT    1,    2)
 1	1
+CREATE TABLE t1 (a INT, b INT, c INT);
+INSERT INTO t1 VALUES (1,1,1), (1,1,1);
+EXPLAIN EXTENDED 
+SELECT c FROM 
+( SELECT 
+(SELECT COUNT(a) FROM 
+(SELECT COUNT(b) FROM t1) AS x GROUP BY c
+) FROM t1 GROUP BY b
+) AS y;
+ERROR 42S22: Unknown column 'c' in 'field list'
+SHOW WARNINGS;
+Level	Code	Message
+Note	1276	Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #2
+Note	1276	Field or reference 'test.t1.c' of SELECT #3 was resolved in SELECT #2
+Error	1054	Unknown column 'c' in 'field list'
+Note	1003	select `c` AS `c` from (select (select count(`test`.`t1`.`a`) AS `COUNT(a)` from (select count(`test`.`t1`.`b`) AS `COUNT(b)` from `test`.`t1`) `x` group by `c`) AS `(SELECT COUNT(a) FROM 
+(SELECT COUNT(b) FROM t1) AS x GROUP BY c
+)` from `test`.`t1` group by `test`.`t1`.`b`) `y`
+DROP TABLE t1;
 End of 5.0 tests

=== modified file 'mysql-test/t/subselect3.test'
--- a/mysql-test/t/subselect3.test	2009-01-28 18:46:45 +0000
+++ b/mysql-test/t/subselect3.test	2009-04-01 21:49:18 +0000
@@ -669,4 +669,23 @@ SELECT ROW(1,2) = (SELECT NULL,    1), R
 SELECT ROW(1,2) = (SELECT    1,    1), ROW(1,2) IN (SELECT    1,    1);
 SELECT ROW(1,2) = (SELECT    1,    2), ROW(1,2) IN (SELECT    1,    2);
 
+#
+# Bug #37362      Crash in do_field_eq
+#
+CREATE TABLE t1 (a INT, b INT, c INT);
+INSERT INTO t1 VALUES (1,1,1), (1,1,1);
+
+--error 1054
+EXPLAIN EXTENDED 
+  SELECT c FROM 
+    ( SELECT 
+      (SELECT COUNT(a) FROM 
+        (SELECT COUNT(b) FROM t1) AS x GROUP BY c
+      ) FROM t1 GROUP BY b
+    ) AS y;
+SHOW WARNINGS;
+
+DROP TABLE t1;
+
+
 --echo End of 5.0 tests

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2009-04-01 11:02:26 +0000
+++ b/sql/sql_select.cc	2009-04-01 21:49:18 +0000
@@ -1953,7 +1953,8 @@ JOIN::exec()
       items3= ref_pointer_array + (all_fields.elements*4);
       setup_copy_fields(thd, &curr_join->tmp_table_param,
 			items3, tmp_fields_list3, tmp_all_fields3,
-			curr_fields_list->elements, *curr_all_fields);
+			curr_fields_list->elements, *curr_all_fields,
+                        tmp_table_field_list);
       tmp_table_param.save_copy_funcs= curr_join->tmp_table_param.copy_funcs;
       tmp_table_param.save_copy_field= curr_join->tmp_table_param.copy_field;
       tmp_table_param.save_copy_field_end=
@@ -2144,6 +2145,26 @@ JOIN::destroy()
   DBUG_ENTER("JOIN::destroy");
   select_lex->join= 0;
 
+  { /*
+      The optimizer pulls up aggregate functions which should be aggregated in
+      an outer select. At some point it may substitute such a function for a
+      field in the temporary table. That temporary table may be closed by
+      JOIN::destroy in case of a parse error in the outer select, so pulled
+      out Item_field of temporary table column has a dangling pointer to
+      freed Field structure. Then this dangling pointer may be accessed by
+      st_select_lex::print() from EXPLAIN EXTENDED query.
+
+      Also an outer query columns may be used in grouping/ordering expressions
+      in this query, and these column references may be substituted with
+      fields in temporary table and cause dangling pointers too.
+
+      To prevent freed memory access we need to cleanup such items.
+    */
+    List_iterator_fast<Item_field> it(tmp_table_field_list);
+    Item_field *item;
+    while ((item= it++))
+      item->cleanup();
+  }
   if (tmp_join)
   {
     if (join_tab != tmp_join->join_tab)
@@ -14184,6 +14205,7 @@ test_if_group_changed(List<Cached_item> 
     res_all_fields - new list of all items
     elements - number of elements in select item list
     all_fields - all fields list
+    tmp_table_fields - only temporary table fields
 
   DESCRIPTION
     Setup copy_fields to save fields at start of new group
@@ -14200,7 +14222,8 @@ bool
 setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
 		  Item **ref_pointer_array,
 		  List<Item> &res_selected_fields, List<Item> &res_all_fields,
-		  uint elements, List<Item> &all_fields)
+		  uint elements, List<Item> &all_fields,
+                  List<Item_field> &tmp_table_fields)
 {
   Item *pos;
   List_iterator_fast<Item> li(all_fields);
@@ -14235,6 +14258,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PA
       Item_field *item;
       if (!(item= new Item_field(thd, ((Item_field*) real_pos))))
 	goto err;
+      tmp_table_fields.push_front(item);
       if (pos->type() == Item::REF_ITEM)
       {
         /* preserve the names of the ref when dereferncing */

=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h	2009-02-05 09:30:39 +0000
+++ b/sql/sql_select.h	2009-04-01 21:49:18 +0000
@@ -325,6 +325,7 @@ public:
   List<Item> tmp_all_fields1, tmp_all_fields2, tmp_all_fields3;
   //Part, shared with list above, emulate following list
   List<Item> tmp_fields_list1, tmp_fields_list2, tmp_fields_list3;
+  List<Item_field> tmp_table_field_list; // Only temporary table fields
   List<Item> &fields_list; // hold field list passed to mysql_select
   List<Item> procedure_fields_list;
   int error;
@@ -503,7 +504,8 @@ void count_field_types(SELECT_LEX *selec
 bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
 		       Item **ref_pointer_array,
 		       List<Item> &new_list1, List<Item> &new_list2,
-		       uint elements, List<Item> &fields);
+		       uint elements, List<Item> &fields,
+                       List<Item_field> &tmp_table_fields);
 void copy_fields(TMP_TABLE_PARAM *param);
 void copy_funcs(Item **func_ptr);
 bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,

Thread
bzr commit into mysql-5.0-bugteam branch (gshchepa:2722) Bug#37362Gleb Shchepa1 Apr