From 9d0c1ce535b57d97cb41dfca47aa33608c38b62d Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Fri, 12 Feb 2010 15:28:38 +0400 Subject: [PATCH] BUG#48438 - crash with error in unioned query against merge table and view... Invalid memory reads after a query referencing MyISAM table multiple times with write lock. Invalid memory reads may lead to server crash, valgrind warnings, incorrect values in INFORMATION_SCHEMA.TABLES.{TABLE_ROWS, DATA_LENGTH, INDEX_LENGTH, ...}. This may happen when one of the table instances gets closed after a query, e.g. out of slots in open tables cache. UNION, MERGE and VIEW are irrelevant. The problem was that MyISAM didn't restore state info pointer to default value. myisam/mi_locking.c: When a query is referencing MyISAM table multiple times with a write lock, all table instances share the same state info, pointing to MI_INFO::save_state of "primary" table instance. When lock is released, state pointer was restored only for the primary table instance. Secondary table instances are still pointing to save_state of primary table instance. Primary table instance may get closed, leaving secondary table instances state pointer pointing to freed memory. That's mostly ok, since next lock will update state info pointer to correct value. But there're some cases, when this secondary table instance state info is accessed without a lock, e.g. INFORMATION_SCHEMA, MERGE (in 5.1 and up), MyISAM itself for DBUG purposes. Restore default value of state pointer unconditionally, for both primary and secondary table instances. mysql-test/r/myisam.result: A test case for BUG#48438. mysql-test/t/myisam.test: A test case for BUG#48438. --- myisam/mi_locking.c | 2 +- mysql-test/r/myisam.result | 13 +++++++++++++ mysql-test/t/myisam.test | 11 +++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c index 42c21b915a5..b9a8e679fc0 100644 --- a/myisam/mi_locking.c +++ b/myisam/mi_locking.c @@ -306,8 +306,8 @@ void mi_update_status(void* param) (long) info->s->state.state.data_file_length)); #endif info->s->state.state= *info->state; - info->state= &info->s->state.state; } + info->state= &info->s->state.state; info->append_insert_at_end= 0; /* diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 9c8e5c2863d..49c09010c58 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -1898,4 +1898,17 @@ CHECKSUM TABLE t1 EXTENDED; Table Checksum test.t1 467455460 DROP TABLE t1; +# +# BUG#48438 - crash with error in unioned query against merge table and view... +# +SET GLOBAL table_cache=3; +CREATE TABLE t1(a INT); +SELECT 1 FROM t1 AS a1, t1 AS a2, t1 AS a3, t1 AS a4 FOR UPDATE; +1 +SELECT TABLE_ROWS, DATA_LENGTH FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'; +TABLE_ROWS DATA_LENGTH +0 0 +DROP TABLE t1; +SET GLOBAL table_cache=DEFAULT; End of 5.0 tests diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index d0a480348a3..936c47a6d08 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -1239,4 +1239,15 @@ CHECKSUM TABLE t1 EXTENDED; DROP TABLE t1; +--echo # +--echo # BUG#48438 - crash with error in unioned query against merge table and view... +--echo # +SET GLOBAL table_cache=3; +CREATE TABLE t1(a INT); +SELECT 1 FROM t1 AS a1, t1 AS a2, t1 AS a3, t1 AS a4 FOR UPDATE; +SELECT TABLE_ROWS, DATA_LENGTH FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'; +DROP TABLE t1; +SET GLOBAL table_cache=DEFAULT; + --echo End of 5.0 tests