MDEV-24620 ASAN heap-buffer-overflow in btr_pcur_restore_position()

Between btr_pcur_store_position() and btr_pcur_restore_position()
it is possible that purge empties a table and enlarges
index->n_core_fields and index->n_core_null_bytes.
Therefore, we must cache index->n_core_fields in
btr_pcur_t::old_n_core_fields so that btr_pcur_t::old_rec can be
parsed correctly.

Unfortunately, this is a huge change, because we will replace
"bool leaf" parameters with "ulint n_core"
(passing index->n_core_fields, or 0 for non-leaf pages).
For special cases where we know that index->is_instant() cannot hold,
we may also pass index->n_fields.
This commit is contained in:
Marko Mäkelä 2021-04-13 10:28:13 +03:00
commit b8c8692fd9
42 changed files with 614 additions and 421 deletions

View file

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation.
Copyright (c) 2017, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -497,8 +497,10 @@ struct btr_pcur_t{
/** if cursor position is stored, contains an initial segment of the
latest record cursor was positioned either on, before or after */
rec_t* old_rec;
/** btr_cur.index->n_core_fields when old_rec was copied */
uint16 old_n_core_fields;
/** number of fields in old_rec */
ulint old_n_fields;
uint16 old_n_fields;
/** BTR_PCUR_ON, BTR_PCUR_BEFORE, or BTR_PCUR_AFTER, depending on
whether cursor was on, before, or after the old_rec record */
enum btr_pcur_pos_t rel_pos;

View file

@ -2,7 +2,7 @@
Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2013, 2020, MariaDB Corporation.
Copyright (c) 2013, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -1348,21 +1348,6 @@ dict_index_build_node_ptr(
ulint level) /*!< in: level of rec in tree:
0 means leaf level */
MY_ATTRIBUTE((nonnull, warn_unused_result));
/**********************************************************************//**
Copies an initial segment of a physical record, long enough to specify an
index entry uniquely.
@return pointer to the prefix record */
rec_t*
dict_index_copy_rec_order_prefix(
/*=============================*/
const dict_index_t* index, /*!< in: index */
const rec_t* rec, /*!< in: record for which to
copy prefix */
ulint* n_fields,/*!< out: number of fields copied */
byte** buf, /*!< in/out: memory buffer for the
copied prefix, or NULL */
ulint* buf_size)/*!< in/out: buffer size */
MY_ATTRIBUTE((nonnull, warn_unused_result));
/** Convert a physical record into a search tuple.
@param[in] rec index record (not necessarily in an index page)
@param[in] index index

View file

@ -2,7 +2,7 @@
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2013, 2020, MariaDB Corporation.
Copyright (c) 2013, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -1070,6 +1070,15 @@ struct dict_index_t{
return DICT_CLUSTERED == (type & (DICT_CLUSTERED | DICT_IBUF));
}
/** @return whether this is a generated clustered index */
bool is_gen_clust() const { return type == DICT_CLUSTERED; }
/** @return whether this is a clustered index */
bool is_clust() const { return type & DICT_CLUSTERED; }
/** @return whether this is a unique index */
bool is_unique() const { return type & DICT_UNIQUE; }
/** @return whether this is a spatial index */
bool is_spatial() const { return UNIV_UNLIKELY(type & DICT_SPATIAL); }

View file

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation.
Copyright (c) 2017, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -57,7 +57,8 @@ rtr_page_cal_mbr(
page = buf_block_get_frame(block);
rec = page_rec_get_next(page_get_infimum_rec(page));
offsets = rec_get_offsets(rec, index, offsets, page_is_leaf(page),
offsets = rec_get_offsets(rec, index, offsets, page_is_leaf(page)
? index->n_fields : 0,
ULINT_UNDEFINED, &heap);
do {

View file

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, 2018, MariaDB Corporation.
Copyright (c) 2015, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -278,7 +278,8 @@ page_cur_tuple_insert(
index, tuple, n_ext);
*offsets = rec_get_offsets(rec, index, *offsets,
page_is_leaf(cursor->block->frame),
page_is_leaf(cursor->block->frame)
? index->n_core_fields : 0,
ULINT_UNDEFINED, heap);
if (buf_block_get_page_zip(cursor->block)) {

View file

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation.
Copyright (c) 2017, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -554,7 +554,7 @@ rec_get_n_extern_new(
@param[in] index the index that the record belongs to
@param[in,out] offsets array comprising offsets[0] allocated elements,
or an array from rec_get_offsets(), or NULL
@param[in] leaf whether this is a leaf-page record
@param[in] n_core 0, or index->n_core_fields for leaf page
@param[in] n_fields maximum number of offsets to compute
(ULINT_UNDEFINED to compute all offsets)
@param[in,out] heap memory heap
@ -564,7 +564,7 @@ rec_get_offsets_func(
const rec_t* rec,
const dict_index_t* index,
rec_offs* offsets,
bool leaf,
ulint n_core,
ulint n_fields,
#ifdef UNIV_DEBUG
const char* file, /*!< in: file name where called */
@ -1121,7 +1121,9 @@ rec_get_converted_size(
The fields are copied into the memory heap.
@param[out] tuple data tuple
@param[in] rec index record, or a copy thereof
@param[in] is_leaf whether rec is a leaf page record
@param[in] index index of rec
@param[in] n_core index->n_core_fields at the time rec was
copied, or 0 if non-leaf page record
@param[in] n_fields number of fields to copy
@param[in,out] heap memory heap */
void
@ -1129,7 +1131,7 @@ rec_copy_prefix_to_dtuple(
dtuple_t* tuple,
const rec_t* rec,
const dict_index_t* index,
bool is_leaf,
ulint n_core,
ulint n_fields,
mem_heap_t* heap)
MY_ATTRIBUTE((nonnull));