#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#37362 | Gleb Shchepa | 1 Apr |