← Back to team overview

maria-developers team mailing list archive

MDEV-10702 Crash in SET STATEMENT FOR EXECUTE

 

  Hello Sergei,

Please review a patch for mdev-10702.diff

Thanks!
diff --git a/mysql-test/r/ps_ddl.result b/mysql-test/r/ps_ddl.result
index dec0d12..fc18322 100644
--- a/mysql-test/r/ps_ddl.result
+++ b/mysql-test/r/ps_ddl.result
@@ -2542,3 +2542,32 @@ EXECUTE stmt3;
 EXECUTE stmt3;
 DEALLOCATE PREPARE stmt3;
 DROP TEMPORARY TABLES tm, t1;
+#
+# Start of 10.1 tests
+#
+#
+# MDEV-10702 Crash in SET STATEMENT FOR EXECUTE
+#
+CREATE TABLE t1 (a INT);
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (@@max_sort_length)';
+SET STATEMENT max_sort_length=2048 FOR EXECUTE stmt;
+SELECT * FROM t1;
+a
+2048
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=NEW.a + 1;
+SET STATEMENT max_sort_length=2048 FOR EXECUTE stmt;
+SELECT * FROM t1;
+a
+2048
+1025
+DROP TRIGGER tr1;
+SET STATEMENT max_sort_length=2048 FOR EXECUTE stmt;
+SELECT * FROM t1;
+a
+2048
+1025
+1024
+DROP TABLE t1;
+#
+# End of 10.1 tests
+#
diff --git a/mysql-test/t/ps_ddl.test b/mysql-test/t/ps_ddl.test
index 21355ca..90226d3 100644
--- a/mysql-test/t/ps_ddl.test
+++ b/mysql-test/t/ps_ddl.test
@@ -2259,3 +2259,27 @@ EXECUTE stmt3;
 EXECUTE stmt3;
 DEALLOCATE PREPARE stmt3;
 DROP TEMPORARY TABLES tm, t1;
+
+--echo #
+--echo # Start of 10.1 tests
+--echo #
+
+--echo #
+--echo # MDEV-10702 Crash in SET STATEMENT FOR EXECUTE
+--echo #
+CREATE TABLE t1 (a INT);
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (@@max_sort_length)';
+SET STATEMENT max_sort_length=2048 FOR EXECUTE stmt;
+SELECT * FROM t1;
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=NEW.a + 1;
+SET STATEMENT max_sort_length=2048 FOR EXECUTE stmt;
+SELECT * FROM t1;
+DROP TRIGGER tr1;
+SET STATEMENT max_sort_length=2048 FOR EXECUTE stmt;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # End of 10.1 tests
+--echo #
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 0db1daa..c0d5460 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -3030,7 +3030,30 @@ void mysql_sql_stmt_execute(THD *thd)
 
   DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt));
 
+  /*
+    thd->free_list can already have some Items,
+    e.g. for a query like this:
+      SET STATEMENT max_sort_length=2048 FOR EXECUTE stmt;
+    thd->free_list contains a pointer to Item_int corresponding to 2048.
+
+    If Prepared_statement::execute() notices that the table metadata for "t1"
+    has changed since PREPARE, it returns an error asking the calling
+    Prepared_statement::execute_loop() to re-prepare the statement.
+    Before returning the error, Prepared_statement::execute()
+    calls Prepared_statement::cleanup_stmt(),
+    which calls thd->cleanup_after_query(),
+    which calls Query_arena::free_items().
+
+    We hide Items created while parsing the "SET STATEMENT" part of the query,
+    so they don't get freed before re-prepare.
+    See MDEV-10702 Crash in SET STATEMENT FOR EXECUTE
+  */
+  Item *free_list_backup= thd->free_list;
+  thd->free_list= NULL;
   (void) stmt->execute_loop(&expanded_query, FALSE, NULL, NULL);
+  thd->free_list= free_list_backup;
+  thd->free_items(); // Now it's OK to free the "SET STATEMENT" Items.
+
   stmt->lex->restore_set_statement_var();
   DBUG_VOID_RETURN;
 }