summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2019-02-05 11:16:43 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2019-02-05 12:02:41 +0200
commit625994b7cc4ebd0bc2652ae80b93386aa4b766ac (patch)
treec18508f1f391e316b049994882fbae50ae024818
parentf53e795250133a622eb1c00271c073726ae3c7fc (diff)
downloadmariadb-git-625994b7cc4ebd0bc2652ae80b93386aa4b766ac.tar.gz
MDEV-16982 Server crashes in mem_heap_dup upon DELETE from table with virtual columns
An uninitialized buffer is passed to row_sel_store_mysql_rec() but InnoDB may not initialize everything. Looks like it's ok in most cases but not always. The partially initialized buffer was later passed to ha_innobase::write_row() which reads random NULL bit values for virtual columns and random stuff happens. No test case for MariaDB 10.2 was found. The test case for MariaDB 10.3 involves partitioning, system versioning and the TRASH_ALLOC fill pattern 0xA5. Test case depends very much on the number and layout of columns. Think about 0xA5 byte for a NULL bit mask. row_sel_store_mysql_rec(): always initialize virtual columns NULL bit Closes #1144
-rw-r--r--storage/innobase/row/row0sel.cc45
1 files changed, 25 insertions, 20 deletions
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index e27b1b9df77..4a82a345a1d 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -2,7 +2,7 @@
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
-Copyright (c) 2015, 2018, MariaDB Corporation.
+Copyright (c) 2015, 2019, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -3132,20 +3132,20 @@ row_sel_store_mysql_field_func(
Note that the template in prebuilt may advise us to copy only a few
columns to mysql_rec, other columns are left blank. All columns may not
be needed in the query.
-@param[out] mysql_rec row in the MySQL format
-@param[in] prebuilt prebuilt structure
-@param[in] rec Innobase record in the index
- which was described in prebuilt's
- template, or in the clustered index;
- must be protected by a page latch
-@param[in] vrow virtual columns
-@param[in] rec_clust whether the rec in the clustered index
-@param[in] index index of rec
-@param[in] offsets array returned by rec_get_offsets(rec)
-@return TRUE on success, FALSE if not all columns could be retrieved */
-static MY_ATTRIBUTE((warn_unused_result))
-ibool
-row_sel_store_mysql_rec(
+@param[out] mysql_rec row in the MySQL format
+@param[in] prebuilt cursor
+@param[in] rec Innobase record in the index
+ which was described in prebuilt's
+ template, or in the clustered index;
+ must be protected by a page latch
+@param[in] vrow virtual columns
+@param[in] rec_clust whether index must be the clustered index
+@param[in] index index of rec
+@param[in] offsets array returned by rec_get_offsets(rec)
+@retval true on success
+@retval false if not all columns could be retrieved */
+MY_ATTRIBUTE((warn_unused_result))
+static bool row_sel_store_mysql_rec(
byte* mysql_rec,
row_prebuilt_t* prebuilt,
const rec_t* rec,
@@ -3167,13 +3167,18 @@ row_sel_store_mysql_rec(
const mysql_row_templ_t*templ = &prebuilt->mysql_template[i];
if (templ->is_virtual && dict_index_is_clust(index)) {
+ /* Virtual columns are never declared NOT NULL. */
+ ut_ad(templ->mysql_null_bit_mask);
/* Skip virtual columns if it is not a covered
search or virtual key read is not requested. */
- if (!dict_index_has_virtual(prebuilt->index)
+ if (!rec_clust
+ || !prebuilt->index->has_virtual()
|| (!prebuilt->read_just_key
- && !prebuilt->m_read_virtual_key)
- || !rec_clust) {
+ && !prebuilt->m_read_virtual_key)) {
+ /* Initialize the NULL bit. */
+ mysql_rec[templ->mysql_null_byte_offset]
+ |= (byte) templ->mysql_null_bit_mask;
continue;
}
@@ -3247,7 +3252,7 @@ row_sel_store_mysql_rec(
rec, index, offsets,
field_no, templ)) {
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(false);
}
}
@@ -3264,7 +3269,7 @@ row_sel_store_mysql_rec(
}
}
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(true);
}
/*********************************************************************//**