summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2021-12-21 11:07:25 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2021-12-21 11:07:25 +0200
commit3b33593f80442214640eefb2ce75c34698c8043b (patch)
tree76c81a12bc2976603812acbcd74cff3c20a5962c
parent3fd80d08740d3ad2426bfb8eb9debc40d96e2a20 (diff)
downloadmariadb-git-3b33593f80442214640eefb2ce75c34698c8043b.tar.gz
MDEV-27332 SIGSEGV in fetch_data_into_cache()
Since commit fb335b48b5e3263698b7d9a74ff3f20ef406df9f we may have a null pointer in purge_sys.query when fetch_data_into_cache() is invoked and innodb_force_recovery>4. This is because the call to purge_sys.create() would be skipped. fetch_data_into_cache(): Load the purge_sys pseudo transaction pointer to a local variable (null pointer if purge_sys is not initialized).
-rw-r--r--mysql-test/suite/innodb/r/read_only_recover_committed.result7
-rw-r--r--mysql-test/suite/innodb/t/read_only_recover_committed.test7
-rw-r--r--storage/innobase/trx/trx0i_s.cc4
3 files changed, 17 insertions, 1 deletions
diff --git a/mysql-test/suite/innodb/r/read_only_recover_committed.result b/mysql-test/suite/innodb/r/read_only_recover_committed.result
index 278905a976b..0bfba662c15 100644
--- a/mysql-test/suite/innodb/r/read_only_recover_committed.result
+++ b/mysql-test/suite/innodb/r/read_only_recover_committed.result
@@ -63,6 +63,13 @@ SELECT * FROM t;
a
3
20
+#
+# MDEV-27332 SIGSEGV in fetch_data_into_cache
+#
+BEGIN;
+SELECT trx_state FROM information_schema.innodb_trx;
+trx_state
+COMMIT;
SELECT * FROM t;
a
3
diff --git a/mysql-test/suite/innodb/t/read_only_recover_committed.test b/mysql-test/suite/innodb/t/read_only_recover_committed.test
index 9ad09bb9b3a..439f57e9fad 100644
--- a/mysql-test/suite/innodb/t/read_only_recover_committed.test
+++ b/mysql-test/suite/innodb/t/read_only_recover_committed.test
@@ -78,6 +78,13 @@ SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT * FROM t;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT * FROM t;
+
+--echo #
+--echo # MDEV-27332 SIGSEGV in fetch_data_into_cache
+--echo #
+BEGIN;
+SELECT trx_state FROM information_schema.innodb_trx;
+COMMIT;
--let $restart_parameters=
--source include/restart_mysqld.inc
SELECT * FROM t;
diff --git a/storage/innobase/trx/trx0i_s.cc b/storage/innobase/trx/trx0i_s.cc
index afd644f3c70..951770e5bb7 100644
--- a/storage/innobase/trx/trx0i_s.cc
+++ b/storage/innobase/trx/trx0i_s.cc
@@ -1275,6 +1275,8 @@ static void fetch_data_into_cache_low(trx_i_s_cache_t *cache, const trx_t *trx)
static void fetch_data_into_cache(trx_i_s_cache_t *cache)
{
+ const trx_t *const purge_trx= purge_sys.query ? purge_sys.query->trx : NULL;
+
ut_ad(lock_mutex_own());
trx_i_s_cache_clear(cache);
@@ -1284,7 +1286,7 @@ static void fetch_data_into_cache(trx_i_s_cache_t *cache)
trx != NULL;
trx= UT_LIST_GET_NEXT(trx_list, trx))
{
- if (trx->state != TRX_STATE_NOT_STARTED && trx != purge_sys.query->trx)
+ if (trx != purge_trx && trx->state != TRX_STATE_NOT_STARTED)
{
mutex_enter(&trx->mutex);
if (trx->state != TRX_STATE_NOT_STARTED)