Details
-
Bug
-
Status: In Review (View Workflow)
-
Critical
-
Resolution: Unresolved
-
10.11.19, 11.4.12
-
Can result in hang or crash
-
Q4/2026 Server Development
Description
Inserting into a SPATIAL index can crash the server with SIGSEGV in rtr_ins_enlarge_mbr().
This happened to me when using an ALTER TABLE t ROW_FORMAT=COMPRESSED; statement on a large table with a spatial index.
Backtrace of the test case below on an unpatched 10.11 debug build:
mariadbd got signal 11 ;
|
Server version: 10.11.19-MariaDB-debug-log
|
bits/stl_vector.h:1224(std::vector<node_visit_t, ut_allocator<node_visit_t, true> >::empty() const)
|
gis/gis0rtree.cc:1248(rtr_ins_enlarge_mbr(btr_cur_t*, mtr_t*))
|
row/row0merge.cc:209(spatial_index_info::insert(unsigned long, btr_pcur_t*, bool&, mem_block_info_t*, mtr_t*))
|
row/row0merge.cc:1766(row_merge_spatial_rows(unsigned long, spatial_index_info**, unsigned long, mem_block_info_t*, btr_pcur_t*, bool&, mtr_t*))
|
row/row0merge.cc:2161(row_merge_read_clustered_index(...))
|
row/row0merge.cc:4782(row_merge_build_indexes(...))
|
handler/handler0alter.cc:8972(ha_innobase::inplace_alter_table(TABLE*, Alter_inplace_info*))
|
sql/handler.h:4626(handler::ha_inplace_alter_table(TABLE*, Alter_inplace_info*))
|
sql/sql_table.cc:8229(mysql_inplace_alter_table(...))
|
sql/sql_table.cc:11575(mysql_alter_table(...))
|
sql/sql_alter.cc:688(Sql_cmd_alter_table::execute(THD*))
|
sql/sql_parse.cc:6190(mysql_execute_command(THD*, bool))
|
MySQL fixed this in 8.0.18 as Bug#28569379 ("ASSERTION FAILURE: SYNC0POLICY.IC.*:M_CONTEXT.M_THREAD_ID == OS_THREAD_ID", commit dcc57a42d1f)
Patch against 10.11 (the DBUG injection point for the test is included) (thanks Claude AI):
diff --git a/storage/innobase/gis/gis0rtree.cc b/storage/innobase/gis/gis0rtree.cc
|
index 47611e8df83..b4350d2c809 100644
|
--- a/storage/innobase/gis/gis0rtree.cc
|
+++ b/storage/innobase/gis/gis0rtree.cc
|
@@ -629,6 +629,7 @@ rtr_adjust_upper_level(
|
|
if (err == DB_FAIL) {
|
cursor.rtr_info = sea_cur->rtr_info;
|
+ cursor.rtr_info_borrowed = true;
|
cursor.tree_height = sea_cur->tree_height;
|
|
/* Recreate a memory heap as input parameter for
|
@@ -1128,6 +1129,11 @@ rtr_page_split_and_insert(
|
rec = NULL;
|
goto after_insert; }
|
);
|
+ DBUG_EXECUTE_IF("rtr_nonleaf_page_need_second_split",
|
+ if (!iterated && page_level) {
|
+ rec = NULL;
|
+ goto after_insert; }
|
+ );
|
|
rec = page_cur_tuple_insert(page_cursor, tuple,
|
offsets, heap, n_ext, mtr);
|
@@ -1189,10 +1195,14 @@ rtr_page_split_and_insert(
|
ibuf_reset_free_bits(block);
|
}
|
|
- /* We need to clean the parent path here and search father
|
- node later, otherwise, it's possible that find a wrong
|
- parent. */
|
- rtr_clean_rtr_info(cursor->rtr_info, true);
|
+ if (!cursor->rtr_info_borrowed) {
|
+ /* We need to clean the parent path here and
|
+ search father node later, otherwise, it's
|
+ possible that find a wrong parent. The search
|
+ path of a borrowed rtr_info is still used by
|
+ its owner. */
|
+ rtr_clean_rtr_info(cursor->rtr_info, true);
|
+ }
|
cursor->rtr_info = NULL;
|
IF_DBUG(iterated=true,);
|
|
diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc
|
index 0c0843a978a..60c8b9a582d 100644
|
--- a/storage/innobase/gis/gis0sea.cc
|
+++ b/storage/innobase/gis/gis0sea.cc
|
@@ -1153,6 +1153,7 @@ static const rec_t* rtr_get_father_node(
|
btr_pcur_get_block(r_cursor),
|
btr_cur_get_page_cur(btr_cur));
|
had_rtr = btr_cur->rtr_info = sea_cur->rtr_info;
|
+ btr_cur->rtr_info_borrowed = true;
|
btr_cur->tree_height = sea_cur->tree_height;
|
}
|
goto func_exit;
|
@@ -1167,6 +1168,7 @@ static const rec_t* rtr_get_father_node(
|
}
|
|
btr_cur->rtr_info = rtr_create_rtr_info(false, false, btr_cur, index);
|
+ btr_cur->rtr_info_borrowed = false;
|
|
if (rtr_search_to_nth_level(level, tuple, PAGE_CUR_RTREE_LOCATE,
|
BTR_CONT_MODIFY_TREE, btr_cur, mtr)
|
diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h
|
index 935be505436..520de3f24c8 100644
|
--- a/storage/innobase/include/btr0cur.h
|
+++ b/storage/innobase/include/btr0cur.h
|
@@ -731,6 +731,9 @@ struct btr_cur_t {
|
flag is BTR_CUR_HASH */
|
/* @} */
|
rtr_info_t* rtr_info; /*!< rtree search info */
|
+ /** whether rtr_info is owned by another cursor, which will
|
+ clean it up */
|
+ bool rtr_info_borrowed;
|
btr_cur_t() { memset((void*) this, 0, sizeof *this); }
|
|
dict_index_t *index() const { return page_cur.index; } |