diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2019-02-05 11:16:43 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2019-02-05 12:02:41 +0200 |
commit | 625994b7cc4ebd0bc2652ae80b93386aa4b766ac (patch) | |
tree | c18508f1f391e316b049994882fbae50ae024818 | |
parent | f53e795250133a622eb1c00271c073726ae3c7fc (diff) | |
download | mariadb-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.cc | 45 |
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); } /*********************************************************************//** |