Commit 2ef2e232 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-29856 heap-use-after-poison in row_merge_spatial_rows() w/ column prefix

spatial_index_info: Replaces index_tuple_info_t. Always take
a memory heap as a parameter to the member functions.
Remove pointer indirection for m_dtuple_vec.

spatial_index_info::add(): Duplicate any PRIMARY KEY fields that would
point to within ext->buf because that buffer will be allocated in
a shorter-lifetime memory heap.
parent b737d09d
...@@ -794,4 +794,14 @@ ENGINE=InnoDB; ...@@ -794,4 +794,14 @@ ENGINE=InnoDB;
INSERT INTO t VALUES (REPEAT('MariaDB Corporation Ab ',351),POINT(0,0)); INSERT INTO t VALUES (REPEAT('MariaDB Corporation Ab ',351),POINT(0,0));
ALTER TABLE t FORCE; ALTER TABLE t FORCE;
DROP TABLE t; DROP TABLE t;
#
# MDEV-29856 heap-use-after-poison in row_merge_spatial_rows()
# with PRIMARY KEY on column prefix
#
CREATE TABLE t (id INT, f TEXT, s POINT NOT NULL,
PRIMARY KEY(id,f(1)), SPATIAL(s)) ENGINE=InnoDB;
INSERT INTO t VALUES
(1,REPEAT('x',8192),@p:=ST_GeomFromText('POINT(0 0)')),(2,'',@p);
ALTER TABLE t FORCE;
DROP TABLE t;
# End of 10.3 tests # End of 10.3 tests
...@@ -793,4 +793,16 @@ ALTER TABLE t FORCE; ...@@ -793,4 +793,16 @@ ALTER TABLE t FORCE;
# Cleanup # Cleanup
DROP TABLE t; DROP TABLE t;
--echo #
--echo # MDEV-29856 heap-use-after-poison in row_merge_spatial_rows()
--echo # with PRIMARY KEY on column prefix
--echo #
CREATE TABLE t (id INT, f TEXT, s POINT NOT NULL,
PRIMARY KEY(id,f(1)), SPATIAL(s)) ENGINE=InnoDB;
INSERT INTO t VALUES
(1,REPEAT('x',8192),@p:=ST_GeomFromText('POINT(0 0)')),(2,'',@p);
ALTER TABLE t FORCE;
DROP TABLE t;
--echo # End of 10.3 tests --echo # End of 10.3 tests
...@@ -60,63 +60,48 @@ Completed by Sunny Bains and Marko Makela ...@@ -60,63 +60,48 @@ Completed by Sunny Bains and Marko Makela
/* Whether to disable file system cache */ /* Whether to disable file system cache */
char srv_disable_sort_file_cache; char srv_disable_sort_file_cache;
/** Class that caches index row tuples made from a single cluster /** Class that caches spatial index row tuples made from a single cluster
index page scan, and then insert into corresponding index tree */ index page scan, and then insert into corresponding index tree */
class index_tuple_info_t { class spatial_index_info {
public: public:
/** constructor /** constructor
@param[in] heap memory heap @param index spatial index to be created */
@param[in] index index to be created */ spatial_index_info(dict_index_t *index) : index(index)
index_tuple_info_t( {
mem_heap_t* heap, ut_ad(index->is_spatial());
dict_index_t* index) UNIV_NOTHROW }
{
m_heap = heap; /** Caches an index row into index tuple vector
m_index = index; @param[in] row table row
m_dtuple_vec = UT_NEW_NOKEY(idx_tuple_vec()); @param[in] ext externally stored column prefixes, or NULL */
} void add(const dtuple_t *row, const row_ext_t *ext, mem_heap_t *heap)
{
/** destructor */ dtuple_t *dtuple= row_build_index_entry(row, ext, index, heap);
~index_tuple_info_t() ut_ad(dtuple);
{ ut_ad(dtuple->n_fields == index->n_fields);
UT_DELETE(m_dtuple_vec); if (ext)
} {
/* Replace any references to ext, because ext will be allocated
/** Get the index object from row_heap. */
@return the index object */ for (ulint i= 1; i < dtuple->n_fields; i++)
dict_index_t* get_index() UNIV_NOTHROW {
{ dfield_t &dfield= dtuple->fields[i];
return(m_index); if (dfield.data >= ext->buf &&
} dfield.data <= &ext->buf[ext->n_ext * ext->max_len])
dfield_dup(&dfield, heap);
/** Caches an index row into index tuple vector }
@param[in] row table row }
@param[in] ext externally stored column m_dtuple_vec.push_back(dtuple);
prefixes, or NULL */ }
void add(
const dtuple_t* row,
const row_ext_t* ext) UNIV_NOTHROW
{
dtuple_t* dtuple;
dtuple = row_build_index_entry(row, ext, m_index, m_heap);
ut_ad(dtuple);
m_dtuple_vec->push_back(dtuple);
}
/** Insert spatial index rows cached in vector into spatial index /** Insert spatial index rows cached in vector into spatial index
@param[in] trx_id transaction id @param[in] trx_id transaction id
@param[in,out] row_heap memory heap
@param[in] pcur cluster index scanning cursor @param[in] pcur cluster index scanning cursor
@param[in,out] heap temporary memory heap
@param[in,out] scan_mtr mini-transaction for pcur @param[in,out] scan_mtr mini-transaction for pcur
@return DB_SUCCESS if successful, else error number */ @return DB_SUCCESS if successful, else error number */
inline dberr_t insert( inline dberr_t insert(trx_id_t trx_id, btr_pcur_t* pcur,
trx_id_t trx_id, mem_heap_t* heap, mtr_t* scan_mtr)
mem_heap_t* row_heap,
btr_pcur_t* pcur,
mtr_t* scan_mtr)
{ {
big_rec_t* big_rec; big_rec_t* big_rec;
rec_t* rec; rec_t* rec;
...@@ -130,14 +115,12 @@ class index_tuple_info_t { ...@@ -130,14 +115,12 @@ class index_tuple_info_t {
| BTR_NO_LOCKING_FLAG | BTR_NO_LOCKING_FLAG
| BTR_KEEP_SYS_FLAG | BTR_CREATE_FLAG; | BTR_KEEP_SYS_FLAG | BTR_CREATE_FLAG;
ut_ad(dict_index_is_spatial(m_index));
DBUG_EXECUTE_IF("row_merge_instrument_log_check_flush", DBUG_EXECUTE_IF("row_merge_instrument_log_check_flush",
log_sys.check_flush_or_checkpoint = true; log_sys.check_flush_or_checkpoint = true;
); );
for (idx_tuple_vec::iterator it = m_dtuple_vec->begin(); for (idx_tuple_vec::iterator it = m_dtuple_vec.begin();
it != m_dtuple_vec->end(); it != m_dtuple_vec.end();
++it) { ++it) {
dtuple = *it; dtuple = *it;
ut_ad(dtuple); ut_ad(dtuple);
...@@ -153,14 +136,14 @@ class index_tuple_info_t { ...@@ -153,14 +136,14 @@ class index_tuple_info_t {
} }
mtr.start(); mtr.start();
m_index->set_modified(mtr); index->set_modified(mtr);
ins_cur.index = m_index; ins_cur.index = index;
rtr_init_rtr_info(&rtr_info, false, &ins_cur, m_index, rtr_init_rtr_info(&rtr_info, false, &ins_cur, index,
false); false);
rtr_info_update_btr(&ins_cur, &rtr_info); rtr_info_update_btr(&ins_cur, &rtr_info);
btr_cur_search_to_nth_level(m_index, 0, dtuple, btr_cur_search_to_nth_level(index, 0, dtuple,
PAGE_CUR_RTREE_INSERT, PAGE_CUR_RTREE_INSERT,
BTR_MODIFY_LEAF, &ins_cur, BTR_MODIFY_LEAF, &ins_cur,
__FILE__, __LINE__, __FILE__, __LINE__,
...@@ -169,44 +152,44 @@ class index_tuple_info_t { ...@@ -169,44 +152,44 @@ class index_tuple_info_t {
/* It need to update MBR in parent entry, /* It need to update MBR in parent entry,
so change search mode to BTR_MODIFY_TREE */ so change search mode to BTR_MODIFY_TREE */
if (rtr_info.mbr_adj) { if (rtr_info.mbr_adj) {
mtr_commit(&mtr); mtr.commit();
rtr_clean_rtr_info(&rtr_info, true); rtr_clean_rtr_info(&rtr_info, true);
rtr_init_rtr_info(&rtr_info, false, &ins_cur, rtr_init_rtr_info(&rtr_info, false, &ins_cur,
m_index, false); index, false);
rtr_info_update_btr(&ins_cur, &rtr_info); rtr_info_update_btr(&ins_cur, &rtr_info);
mtr_start(&mtr); mtr.start();
m_index->set_modified(mtr); index->set_modified(mtr);
btr_cur_search_to_nth_level( btr_cur_search_to_nth_level(
m_index, 0, dtuple, index, 0, dtuple,
PAGE_CUR_RTREE_INSERT, PAGE_CUR_RTREE_INSERT,
BTR_MODIFY_TREE, &ins_cur, BTR_MODIFY_TREE, &ins_cur,
__FILE__, __LINE__, &mtr); __FILE__, __LINE__, &mtr);
} }
error = btr_cur_optimistic_insert( error = btr_cur_optimistic_insert(
flag, &ins_cur, &ins_offsets, &row_heap, flag, &ins_cur, &ins_offsets, &heap,
dtuple, &rec, &big_rec, 0, NULL, &mtr); dtuple, &rec, &big_rec, 0, NULL, &mtr);
if (error == DB_FAIL) { if (error == DB_FAIL) {
ut_ad(!big_rec); ut_ad(!big_rec);
mtr.commit(); mtr.commit();
mtr.start(); mtr.start();
m_index->set_modified(mtr); index->set_modified(mtr);
rtr_clean_rtr_info(&rtr_info, true); rtr_clean_rtr_info(&rtr_info, true);
rtr_init_rtr_info(&rtr_info, false, rtr_init_rtr_info(&rtr_info, false,
&ins_cur, m_index, false); &ins_cur, index, false);
rtr_info_update_btr(&ins_cur, &rtr_info); rtr_info_update_btr(&ins_cur, &rtr_info);
btr_cur_search_to_nth_level( btr_cur_search_to_nth_level(
m_index, 0, dtuple, index, 0, dtuple,
PAGE_CUR_RTREE_INSERT, PAGE_CUR_RTREE_INSERT,
BTR_MODIFY_TREE, BTR_MODIFY_TREE,
&ins_cur, __FILE__, __LINE__, &mtr); &ins_cur, __FILE__, __LINE__, &mtr);
error = btr_cur_pessimistic_insert( error = btr_cur_pessimistic_insert(
flag, &ins_cur, &ins_offsets, flag, &ins_cur, &ins_offsets,
&row_heap, dtuple, &rec, &heap, dtuple, &rec,
&big_rec, 0, NULL, &mtr); &big_rec, 0, NULL, &mtr);
} }
...@@ -229,30 +212,26 @@ class index_tuple_info_t { ...@@ -229,30 +212,26 @@ class index_tuple_info_t {
} }
} }
mtr_commit(&mtr); mtr.commit();
rtr_clean_rtr_info(&rtr_info, true); rtr_clean_rtr_info(&rtr_info, true);
} }
m_dtuple_vec->clear(); m_dtuple_vec.clear();
return(error); return(error);
} }
private: private:
/** Cache index rows made from a cluster index scan. Usually /** Cache index rows made from a cluster index scan. Usually
for rows on single cluster index page */ for rows on single cluster index page */
typedef std::vector<dtuple_t*, ut_allocator<dtuple_t*> > typedef std::vector<dtuple_t*, ut_allocator<dtuple_t*> > idx_tuple_vec;
idx_tuple_vec;
/** vector used to cache index rows made from cluster index scan */ /** vector used to cache index rows made from cluster index scan */
idx_tuple_vec* m_dtuple_vec; idx_tuple_vec m_dtuple_vec;
public:
/** the index being built */ /** the index being built */
dict_index_t* m_index; dict_index_t*const index;
/** memory heap for creating index tuples */
mem_heap_t* m_heap;
}; };
/* Maximum pending doc memory limit in bytes for a fts tokenization thread */ /* Maximum pending doc memory limit in bytes for a fts tokenization thread */
...@@ -1566,7 +1545,6 @@ row_mtuple_cmp( ...@@ -1566,7 +1545,6 @@ row_mtuple_cmp(
@param[in] trx_id transaction id @param[in] trx_id transaction id
@param[in] sp_tuples cached spatial rows @param[in] sp_tuples cached spatial rows
@param[in] num_spatial number of spatial indexes @param[in] num_spatial number of spatial indexes
@param[in,out] row_heap heap for insert
@param[in,out] sp_heap heap for tuples @param[in,out] sp_heap heap for tuples
@param[in,out] pcur cluster index cursor @param[in,out] pcur cluster index cursor
@param[in,out] mtr mini transaction @param[in,out] mtr mini transaction
...@@ -1575,9 +1553,8 @@ static ...@@ -1575,9 +1553,8 @@ static
dberr_t dberr_t
row_merge_spatial_rows( row_merge_spatial_rows(
trx_id_t trx_id, trx_id_t trx_id,
index_tuple_info_t** sp_tuples, spatial_index_info** sp_tuples,
ulint num_spatial, ulint num_spatial,
mem_heap_t* row_heap,
mem_heap_t* sp_heap, mem_heap_t* sp_heap,
btr_pcur_t* pcur, btr_pcur_t* pcur,
mtr_t* mtr) mtr_t* mtr)
...@@ -1591,7 +1568,7 @@ row_merge_spatial_rows( ...@@ -1591,7 +1568,7 @@ row_merge_spatial_rows(
ut_ad(sp_heap != NULL); ut_ad(sp_heap != NULL);
for (ulint j = 0; j < num_spatial; j++) { for (ulint j = 0; j < num_spatial; j++) {
err = sp_tuples[j]->insert(trx_id, row_heap, pcur, mtr); err = sp_tuples[j]->insert(trx_id, pcur, sp_heap, mtr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
return(err); return(err);
...@@ -1714,8 +1691,7 @@ row_merge_read_clustered_index( ...@@ -1714,8 +1691,7 @@ row_merge_read_clustered_index(
os_event_t fts_parallel_sort_event = NULL; os_event_t fts_parallel_sort_event = NULL;
ibool fts_pll_sort = FALSE; ibool fts_pll_sort = FALSE;
int64_t sig_count = 0; int64_t sig_count = 0;
index_tuple_info_t** sp_tuples = NULL; spatial_index_info** sp_tuples = NULL;
mem_heap_t* sp_heap = NULL;
ulint num_spatial = 0; ulint num_spatial = 0;
BtrBulk* clust_btr_bulk = NULL; BtrBulk* clust_btr_bulk = NULL;
bool clust_temp_file = false; bool clust_temp_file = false;
...@@ -1805,9 +1781,7 @@ row_merge_read_clustered_index( ...@@ -1805,9 +1781,7 @@ row_merge_read_clustered_index(
if (num_spatial > 0) { if (num_spatial > 0) {
ulint count = 0; ulint count = 0;
sp_heap = mem_heap_create(512); sp_tuples = static_cast<spatial_index_info**>(
sp_tuples = static_cast<index_tuple_info_t**>(
ut_malloc_nokey(num_spatial ut_malloc_nokey(num_spatial
* sizeof(*sp_tuples))); * sizeof(*sp_tuples)));
...@@ -1815,9 +1789,7 @@ row_merge_read_clustered_index( ...@@ -1815,9 +1789,7 @@ row_merge_read_clustered_index(
if (dict_index_is_spatial(index[i])) { if (dict_index_is_spatial(index[i])) {
sp_tuples[count] sp_tuples[count]
= UT_NEW_NOKEY( = UT_NEW_NOKEY(
index_tuple_info_t( spatial_index_info(index[i]));
sp_heap,
index[i]));
count++; count++;
} }
} }
...@@ -1948,7 +1920,7 @@ row_merge_read_clustered_index( ...@@ -1948,7 +1920,7 @@ row_merge_read_clustered_index(
/* Insert the cached spatial index rows. */ /* Insert the cached spatial index rows. */
err = row_merge_spatial_rows( err = row_merge_spatial_rows(
trx->id, sp_tuples, num_spatial, trx->id, sp_tuples, num_spatial,
row_heap, sp_heap, &pcur, &mtr); row_heap, &pcur, &mtr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
goto func_exit; goto func_exit;
...@@ -2329,7 +2301,7 @@ row_merge_read_clustered_index( ...@@ -2329,7 +2301,7 @@ row_merge_read_clustered_index(
continue; continue;
} }
ut_ad(sp_tuples[s_idx_cnt]->get_index() ut_ad(sp_tuples[s_idx_cnt]->index
== buf->index); == buf->index);
/* If the geometry field is invalid, report /* If the geometry field is invalid, report
...@@ -2339,7 +2311,7 @@ row_merge_read_clustered_index( ...@@ -2339,7 +2311,7 @@ row_merge_read_clustered_index(
break; break;
} }
sp_tuples[s_idx_cnt]->add(row, ext); sp_tuples[s_idx_cnt]->add(row, ext, buf->heap);
s_idx_cnt++; s_idx_cnt++;
continue; continue;
...@@ -2469,7 +2441,7 @@ row_merge_read_clustered_index( ...@@ -2469,7 +2441,7 @@ row_merge_read_clustered_index(
err = row_merge_spatial_rows( err = row_merge_spatial_rows(
trx->id, sp_tuples, trx->id, sp_tuples,
num_spatial, num_spatial,
row_heap, sp_heap, row_heap,
&pcur, &mtr); &pcur, &mtr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
...@@ -2847,10 +2819,6 @@ row_merge_read_clustered_index( ...@@ -2847,10 +2819,6 @@ row_merge_read_clustered_index(
UT_DELETE(sp_tuples[i]); UT_DELETE(sp_tuples[i]);
} }
ut_free(sp_tuples); ut_free(sp_tuples);
if (sp_heap) {
mem_heap_free(sp_heap);
}
} }
/* Update the next Doc ID we used. Table should be locked, so /* Update the next Doc ID we used. Table should be locked, so
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment