summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Shulga <dmitry.shulga@mariadb.com>2022-04-11 13:37:55 +0700
committerDmitry Shulga <dmitry.shulga@mariadb.com>2022-04-11 13:37:55 +0700
commit1d52bf0ac68133a1292a131bee49fcf4e3132540 (patch)
tree58a3eef8482830906c278d90680639927de111dd
parent27b5d814e2c851569a0d75e4217da4a552b79f25 (diff)
downloadmariadb-git-bb-10.2-MDEV-16128.tar.gz
MDEV-16128: Server crash in Item_func::print_op on 2nd execution of PSbb-10.2-MDEV-16128
For some queries that involve tables with different but convertible character sets for columns taking part in the query, repeatable execution of such queries in PS mode or as part of a stored routine would result in server abnormal termination. For example, CREATE TABLE t1 (a2 varchar(10)); CREATE TABLE t2 (u1 varchar(10) CHARACTER SET utf8); CREATE TABLE t3 (u2 varchar(10) CHARACTER SET utf8); PREPARE stmt FROM "SELECT t1.* FROM (t1 JOIN t2 ON (t2.u1 = t1.a2)) WHERE (EXISTS (SELECT 1 FROM t3 WHERE t3.u2 = t1.a2))"; EXECUTE stmt; EXECUTE stmt; <== Running this prepared statement the second time results in server crash. The reason of server crash is that an instance of the class Item_func_conv_charset, that created for conversion of a column from one character set to another, is allocated on execution memory root but pointer to this instance is stored in an item placed on prepared statement memory root. Below is calls trace to the place where an instance of the class Item_func_conv_charset is created. setup_conds Item_func::fix_fields Item_bool_rowready_func2::fix_length_and_dec Item_func::setup_args_and_comparator Item_func_or_sum::agg_arg_charsets_for_comparison Item_func_or_sum::agg_arg_charsets Item_func_or_sum::agg_item_set_converter Item::safe_charset_converter And the following trace shows the point where a pointer to the instance of Item_func_conv_charset is passed to the class Item_func_eq, that is created on a memory root of the prepared statement. Prepared_statement::execute mysql_execute_command execute_sqlcom_select handle_select mysql_select JOIN::optimize JOIN::optimize_inner convert_join_subqueries_to_semijoins convert_subq_to_sj --- Item_func_eq *item_eq= new (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr_orig, subq_lex->ref_pointer_array[0]); On completing execution of the statement EXECUTE stmt the items placed on execution query arena are released but the instance of Item_func_eq that was created on permanent memory root still does exist and has one of its arguments (stored in args[0]) referencing to the released object. Next time the prepared statement is executed access to dangling pointer leads to server crash. So, to fix the issue the item Item_func_conv_charset should be created on permanent memory root in case a prepared statement or stored routine is run.
-rw-r--r--mysql-test/r/ps.result16
-rw-r--r--mysql-test/t/ps.test16
-rw-r--r--sql/item_cmpfunc.cc14
3 files changed, 45 insertions, 1 deletions
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result
index 81167bc85c0..77bfcb9eabb 100644
--- a/mysql-test/r/ps.result
+++ b/mysql-test/r/ps.result
@@ -5509,5 +5509,21 @@ id select_type table type possible_keys key key_len ref rows Extra
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL
DEALLOCATE PREPARE stmt;
DROP TABLE t1;
+#
+# MDEV-16128: Server crash in Item_func::print_op on 2nd execution of PS
+#
+CREATE TABLE t1 (a2 varchar(10));
+CREATE TABLE t2 (u1 varchar(10) CHARACTER SET utf8 );
+CREATE TABLE t3 (u2 varchar(10) CHARACTER SET utf8);
+PREPARE stmt FROM "SELECT t1.* FROM (t1 JOIN t2 ON (t2.u1 = t1.a2)) WHERE (EXISTS (SELECT 1 FROM t3 WHERE t3.u2 = t1.a2))";
+EXECUTE stmt;
+a2
+# Without the patch second execution of the prepared statement
+# would lead to server crash.
+EXECUTE stmt;
+a2
+# Clean up
+DEALLOCATE PREPARE stmt;
+DROP TABLE t1, t2, t3;
# End of 10.2 tests
#
diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test
index 81d8e8e0fed..233ef8c369c 100644
--- a/mysql-test/t/ps.test
+++ b/mysql-test/t/ps.test
@@ -4990,5 +4990,21 @@ EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DROP TABLE t1;
+--echo #
+--echo # MDEV-16128: Server crash in Item_func::print_op on 2nd execution of PS
+--echo #
+
+CREATE TABLE t1 (a2 varchar(10));
+CREATE TABLE t2 (u1 varchar(10) CHARACTER SET utf8 );
+CREATE TABLE t3 (u2 varchar(10) CHARACTER SET utf8);
+PREPARE stmt FROM "SELECT t1.* FROM (t1 JOIN t2 ON (t2.u1 = t1.a2)) WHERE (EXISTS (SELECT 1 FROM t3 WHERE t3.u2 = t1.a2))";
+EXECUTE stmt;
+--echo # Without the patch second execution of the prepared statement
+--echo # would lead to server crash.
+EXECUTE stmt;
+--echo # Clean up
+DEALLOCATE PREPARE stmt;
+DROP TABLE t1, t2, t3;
+
--echo # End of 10.2 tests
--echo #
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 3a76982d80e..19bd6176bd1 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -513,19 +513,31 @@ bool Item_func::setup_args_and_comparator(THD *thd, Arg_comparator *cmp)
{
DBUG_ASSERT(arg_count >= 2); // Item_func_nullif has arg_count == 3
+ Query_arena *arena, backup;
+ arena= thd->activate_stmt_arena_if_needed(&backup);
+
if (args[0]->cmp_type() == STRING_RESULT &&
args[1]->cmp_type() == STRING_RESULT)
{
DTCollation tmp;
if (agg_arg_charsets_for_comparison(tmp, args, 2))
+ {
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+
return true;
+ }
cmp->m_compare_collation= tmp.collation;
}
// Convert constants when compared to int/year field
DBUG_ASSERT(functype() != LIKE_FUNC);
convert_const_compared_to_int_field(thd);
- return cmp->set_cmp_func(this, &args[0], &args[1], true);
+ bool ret= cmp->set_cmp_func(this, &args[0], &args[1], true);
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+
+ return ret;
}