diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-07-31 11:38:23 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2020-07-31 11:54:35 +0300 |
commit | f35d1721039f8f115fc55e8f4b4d2bb4012161d1 (patch) | |
tree | fb8932f642c981958ae7e6140ae0dae2b95c9ec4 | |
parent | fd0abc890f99e2b5ca1b8ae4cb0dc3968eef1208 (diff) | |
download | mariadb-git-f35d1721039f8f115fc55e8f4b4d2bb4012161d1.tar.gz |
MDEV-23198 Crash in REPLACE
row_vers_impl_x_locked_low(): clust_offsets may point to memory
that is allocated by mem_heap_alloc() and may have been freed.
For initializing clust_offsets, try to use the stack-allocated
buffer instead of a pointer that may point to freed memory.
This fixes a regression that was introduced in
commit f0aa073f2bf3d8d85b3d028df89cdb4cdfc4002d (MDEV-20950).
-rw-r--r-- | mysql-test/suite/innodb/r/mvcc.result | 14 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/mvcc.test | 20 | ||||
-rw-r--r-- | storage/innobase/row/row0vers.cc | 8 |
3 files changed, 38 insertions, 4 deletions
diff --git a/mysql-test/suite/innodb/r/mvcc.result b/mysql-test/suite/innodb/r/mvcc.result index 6826978d6a7..b0b834c91a4 100644 --- a/mysql-test/suite/innodb/r/mvcc.result +++ b/mysql-test/suite/innodb/r/mvcc.result @@ -28,4 +28,18 @@ SELECT * FROM t1; a 0 DROP TABLE t1; +# +# MDEV-23198 Crash in REPLACE +# +BEGIN NOT ATOMIC +DECLARE c TEXT DEFAULT(SELECT CONCAT('CREATE TABLE t1(id INT PRIMARY KEY, c', +GROUP_CONCAT(seq SEPARATOR ' INT, c'), +' INT NOT NULL UNIQUE) ENGINE=InnoDB') +FROM seq_1_to_294); +EXECUTE IMMEDIATE c; +END; +$$ +INSERT INTO t1 SET id=1,c294=1; +REPLACE t1 SET id=1,c294=1; +DROP TABLE t1; SET GLOBAL innodb_file_per_table= @save_per_table; diff --git a/mysql-test/suite/innodb/t/mvcc.test b/mysql-test/suite/innodb/t/mvcc.test index bf76a5de798..7c37718c28a 100644 --- a/mysql-test/suite/innodb/t/mvcc.test +++ b/mysql-test/suite/innodb/t/mvcc.test @@ -1,4 +1,5 @@ --source include/have_innodb.inc +--source include/have_sequence.inc SET @save_per_table= @@GLOBAL.innodb_file_per_table; SET GLOBAL innodb_file_per_table= 1; @@ -49,4 +50,23 @@ SELECT * FROM t1; DROP TABLE t1; +--echo # +--echo # MDEV-23198 Crash in REPLACE +--echo # + +DELIMITER $$; +BEGIN NOT ATOMIC + DECLARE c TEXT DEFAULT(SELECT CONCAT('CREATE TABLE t1(id INT PRIMARY KEY, c', + GROUP_CONCAT(seq SEPARATOR ' INT, c'), + ' INT NOT NULL UNIQUE) ENGINE=InnoDB') + FROM seq_1_to_294); + EXECUTE IMMEDIATE c; +END; +$$ +DELIMITER ;$$ + +INSERT INTO t1 SET id=1,c294=1; +REPLACE t1 SET id=1,c294=1; +DROP TABLE t1; + SET GLOBAL innodb_file_per_table= @save_per_table; diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc index 09509444ea4..77bbb1b3459 100644 --- a/storage/innobase/row/row0vers.cc +++ b/storage/innobase/row/row0vers.cc @@ -91,7 +91,7 @@ row_vers_impl_x_locked_low( { rec_t* prev_version = NULL; rec_offs clust_offsets_[REC_OFFS_NORMAL_SIZE]; - rec_offs* clust_offsets = clust_offsets_; + rec_offs* clust_offsets; mem_heap_t* heap; dtuple_t* ientry = NULL; mem_heap_t* v_heap = NULL; @@ -105,7 +105,7 @@ row_vers_impl_x_locked_low( heap = mem_heap_create(1024); - clust_offsets = rec_get_offsets(clust_rec, clust_index, clust_offsets, + clust_offsets = rec_get_offsets(clust_rec, clust_index, clust_offsets_, true, ULINT_UNDEFINED, &heap); const trx_id_t trx_id = row_get_rec_trx_id( @@ -187,7 +187,7 @@ row_vers_impl_x_locked_low( ut_ad(committed || prev_version || !rec_get_deleted_flag(version, comp)); - /* Free version. */ + /* Free version and clust_offsets. */ mem_heap_free(old_heap); if (committed) { @@ -222,7 +222,7 @@ not_locked: } clust_offsets = rec_get_offsets( - prev_version, clust_index, clust_offsets, true, + prev_version, clust_index, clust_offsets_, true, ULINT_UNDEFINED, &heap); vers_del = rec_get_deleted_flag(prev_version, comp); |