From d56f5dae1ef60468dd7497453bcdca9b653922ca Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 23 May 2012 18:18:08 +0300 Subject: [PATCH] Fix bug lp:1001506 This is a backport of the (unchaged) fix for MySQL bug #11764372, 57197. Analysis: When the outer query finishes its main execution and computes GROUP BY, it needs to construct a new temporary table (and a corresponding JOIN) to execute the last DISTINCT operation. At this point JOIN::exec calls JOIN::join_free, which calls JOIN::cleanup -> TMP_TABLE_PARAM::cleanup for both the outer and the inner JOINs. The call to the inner TMP_TABLE_PARAM::cleanup sets copy_field = NULL, but not copy_field_end. The final execution phase that computes the DISTINCT invokes: evaluate_join_record -> end_write -> copy_funcs The last function copies the results of all functions into the temp table. copy_funcs walks over all functions in join->tmp_table_param.items_to_copy. In this case items_to_copy contains both assignments to user variables. The process of copying user variables invokes Item_func_set_user_var::check which in turn re-evaluates the arguments of the user variable assignment. This in turn triggers re-evaluation of the subquery, and ultimately copy_field. However, the previous call to TMP_TABLE_PARAM::cleanup for the subquery already set copy_field to NULL but not its copy_field_end. This results in a null pointer access, and a crash. Fix: Set copy_field_end and save_copy_field_end to null when deleting copy fields in TMP_TABLE_PARAM::cleanup(). --- mysql-test/r/user_var.result | 7 +++++++ mysql-test/t/user_var.test | 11 +++++++++++ sql/sql_class.h | 3 ++- sql/sql_select.cc | 2 ++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 374520ff610..19cb54ad2bc 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -456,4 +456,11 @@ SELECT (@v:=a) <> (@v:=1) FROM t1; (@v:=a) <> (@v:=1) 1 DROP TABLE t1; +CREATE TABLE t1(a int); +INSERT INTO t1 VALUES (1), (2); +SELECT DISTINCT @a:=MIN(t1.a) FROM t1, t1 AS t2 +GROUP BY @b:=(SELECT COUNT(*) > t2.a); +@a:=MIN(t1.a) +1 +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index efaf8afd91e..2782f61994d 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -365,4 +365,15 @@ SELECT (@v:=a) <> (@v:=1) FROM t1; DROP TABLE t1; +# +# LP BUG#1001506 Crash on a query with GROUP BY and user variables +# MySQL Bug #11764372 57197: EVEN MORE USER VARIABLE CRASHING FUN +# + +CREATE TABLE t1(a int); +INSERT INTO t1 VALUES (1), (2); +SELECT DISTINCT @a:=MIN(t1.a) FROM t1, t1 AS t2 +GROUP BY @b:=(SELECT COUNT(*) > t2.a); +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/sql/sql_class.h b/sql/sql_class.h index 4bf1bc3964c..14f4f022de3 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2880,7 +2880,8 @@ public: if (copy_field) /* Fix for Intel compiler */ { delete [] copy_field; - save_copy_field= copy_field= 0; + save_copy_field= copy_field= NULL; + save_copy_field_end= copy_field_end= NULL; } } }; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 150f19f96a6..46b4511e24f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -16072,6 +16072,8 @@ copy_fields(TMP_TABLE_PARAM *param) Copy_field *ptr=param->copy_field; Copy_field *end=param->copy_field_end; + DBUG_ASSERT((ptr != NULL && end >= ptr) || (ptr == NULL && end == NULL)); + for (; ptr != end; ptr++) (*ptr->do_copy)(ptr);