Bug #95272 Potential InnoDB SPATIAL INDEX corruption during root page split
Submitted: 7 May 2019 9:05 Modified: 7 May 2019 12:12
Reporter: Qingda Hu Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: InnoDB storage engine Severity:S2 (Serious)
Version:5.7, 5.7.26 OS:Any
Assigned to: CPU Architecture:Any

[7 May 2019 9:05] Qingda Hu
Description:
The bug is confirmed in MariaDB (MDEV-13942: https://jira.mariadb.org/browse/MDEV-13942)

This was reported by Valgrind when running the test innodb.instant_alter.

==28026== Conditional jump or move depends on uninitialised value(s)
==28026==    at 0x100CC24: dtuple_get_nth_field(dtuple_t const*, unsigned long) (data0data.ic:433)
==28026==    by 0x1011D79: rtr_page_split_initialize_nodes(mem_block_info_t*, btr_cur_t*, unsigned long**, dtuple_t const*, double**) (gis0rtree.cc:108)
==28026==    by 0x1014828: rtr_page_split_and_insert(unsigned long, btr_cur_t*, unsigned long**, mem_block_info_t**, dtuple_t const*, unsigned long, mtr_t*) (gis0rtree.cc:1064)
==28026==    by 0xEA8B36: btr_root_raise_and_insert(unsigned long, btr_cur_t*, unsigned long**, mem_block_info_t**, dtuple_t const*, unsigned long, mtr_t*) (btr0btr.cc:2101)
==28026==    by 0xECF378: btr_cur_pessimistic_insert(unsigned long, btr_cur_t*, unsigned long**, mem_block_info_t**, dtuple_t*, unsigned char**, big_rec_t**, unsigned long, que_thr_t*, mtr_t*) (btr0cur.cc:3352)
==28026==    by 0x1013763: rtr_adjust_upper_level(btr_cur_t*, unsigned long, buf_block_t*, buf_block_t*, rtr_mbr*, rtr_mbr*, unsigned long, mtr_t*) (gis0rtree.cc:730)
==28026==    by 0x101529E: rtr_page_split_and_insert(unsigned long, btr_cur_t*, unsigned long**, mem_block_info_t**, dtuple_t const*, unsigned long, mtr_t*) (gis0rtree.cc:1275)

The problem is in rtr_adjust_upper_level(), which allocates node_ptr from heap, and then passes the same heap to btr_cur_pessimistic_insert(). The documentation of btr_cur_pessimistic_insert() says that the heap can be emptied. If the heap is emptied and something else is allocated from the heap, the node_ptr can become corrupted.

How to repeat:
Marko propose a simple way to repeat the bug in MySQL-5.7.25 (https://jira.mariadb.org/browse/MDEV-13942).

Suggested fix:
In rtr_adjust_upper_level(),  we can recreate a memory heap as input parameter for btr_cur_pessimistic_insert(), because the heap may be emptied in btr_cur_pessimistic_insert(). 

         rtr_adjust_upper_level()
         {
                ...
		mem_heap_t* new_heap = mem_heap_create(1024);

		err = btr_cur_pessimistic_insert(flags
						 | BTR_NO_LOCKING_FLAG
						 | BTR_KEEP_SYS_FLAG
						 | BTR_NO_UNDO_LOG_FLAG,
						 &cursor, &offsets, &new_heap,
						 node_ptr_upper, &rec,
						 &dummy_big_rec, 0, NULL, mtr);
		cursor.rtr_info = NULL;
		ut_a(err == DB_SUCCESS);

		mem_heap_free(new_heap);
                ...
	}

Just like commit#1214674 to mariadb: 
https://github.com/MariaDB/server/commit/1214674b712d855d7cd04f4daedb9a16c24fc63b
[7 May 2019 12:12] MySQL Verification Team
Hello Albert Hu,

Thank you for the report.

regards,
Umesh