summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2020-07-31 11:38:23 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2020-07-31 11:54:35 +0300
commitf35d1721039f8f115fc55e8f4b4d2bb4012161d1 (patch)
treefb8932f642c981958ae7e6140ae0dae2b95c9ec4
parentfd0abc890f99e2b5ca1b8ae4cb0dc3968eef1208 (diff)
downloadmariadb-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.result14
-rw-r--r--mysql-test/suite/innodb/t/mvcc.test20
-rw-r--r--storage/innobase/row/row0vers.cc8
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);