Skip to content

Commit 2728bb8

Browse files
committed
Bug #20582149 INVALID READ OF SIZE 1 IN PROTOCOL::NET_STORE_DATA
Problem: The row_prebuilt_t structure has a member blob_heap. In this memory heap, externally stored field data will be copied and passed on to the higher layer. Between each row this memory heap will be re-initialized. In native partitioning, only one row_prebuilt_t structure will be there for a partitioned table. So there was only one blob_heap available. This resulted in free memory read (FMR) issue. Solution: The ha_innopart class needs to maintain an array of memory heaps, one for each partition. The row_prebuilt_t::blob_heap needs to be updated according to the partition accessed. rb#8121 approved by Mattias and Krunal.
1 parent 7f166d9 commit 2728bb8

File tree

6 files changed

+248
-19
lines changed

6 files changed

+248
-19
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#
2+
# Bug #20582149 INVALID READ OF SIZE 1 IN PROTOCOL::NET_STORE_DATA
3+
#
4+
CREATE TABLE t1 (f1 INT NOT NULL, f2 text,
5+
PRIMARY KEY(f1)) PARTITION BY KEY() PARTITIONS 4;
6+
INSERT INTO t1 VALUES(42,'Testing MySQL databases is a cool ');
7+
INSERT INTO t1 VALUES(2,'Testing MySQL databases is a cool ');
8+
INSERT INTO t1 VALUES(4,'Testing MySQL databases is a cool ');
9+
select f1, f2 from t1 order by f1;
10+
f1 f2
11+
2 Testing MySQL databases is a cool
12+
4 Testing MySQL databases is a cool
13+
42 Testing MySQL databases is a cool
14+
DROP TABLE IF EXISTS t1;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--source include/have_partition.inc
2+
--source include/have_innodb.inc
3+
4+
--echo #
5+
--echo # Bug #20582149 INVALID READ OF SIZE 1 IN PROTOCOL::NET_STORE_DATA
6+
--echo #
7+
8+
CREATE TABLE t1 (f1 INT NOT NULL, f2 text,
9+
PRIMARY KEY(f1)) PARTITION BY KEY() PARTITIONS 4;
10+
11+
INSERT INTO t1 VALUES(42,'Testing MySQL databases is a cool ');
12+
INSERT INTO t1 VALUES(2,'Testing MySQL databases is a cool ');
13+
INSERT INTO t1 VALUES(4,'Testing MySQL databases is a cool ');
14+
15+
select f1, f2 from t1 order by f1;
16+
17+
DROP TABLE IF EXISTS t1;
18+

storage/innobase/handler/ha_innopart.cc

+157-4
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,7 @@ ha_innopart::ha_innopart(
710710
Partition_helper(this),
711711
m_ins_node_parts(),
712712
m_upd_node_parts(),
713+
m_blob_heap_parts(),
713714
m_trx_id_parts(),
714715
m_row_read_type_parts(),
715716
m_sql_stat_start_parts(),
@@ -1223,6 +1224,9 @@ ha_innopart::open(
12231224
ut_malloc(sizeof(*m_upd_node_parts)
12241225
* m_tot_parts,
12251226
mem_key_partitioning));
1227+
1228+
alloc_blob_heap_array();
1229+
12261230
m_trx_id_parts = static_cast<trx_id_t*>(
12271231
ut_malloc(sizeof(*m_trx_id_parts)
12281232
* m_tot_parts,
@@ -1236,6 +1240,7 @@ ha_innopart::open(
12361240
mem_key_partitioning));
12371241
if (m_ins_node_parts == NULL
12381242
|| m_upd_node_parts == NULL
1243+
|| m_blob_heap_parts == NULL
12391244
|| m_trx_id_parts == NULL
12401245
|| m_row_read_type_parts == NULL
12411246
|| m_sql_stat_start_parts == NULL) {
@@ -1356,6 +1361,7 @@ ha_innopart::close()
13561361
m_part_share = NULL;
13571362
}
13581363
clear_ins_upd_nodes();
1364+
free_blob_heap_array();
13591365

13601366
/* Prevent double close of m_prebuilt->table. The real one was done
13611367
done in m_part_share->close_table_parts(). */
@@ -1408,9 +1414,13 @@ void
14081414
ha_innopart::set_partition(
14091415
uint part_id)
14101416
{
1417+
DBUG_ENTER("ha_innopart::set_partition");
1418+
1419+
DBUG_PRINT("ha_innopart", ("partition id: %u", part_id));
1420+
14111421
if (part_id >= m_tot_parts) {
14121422
ut_ad(0);
1413-
return;
1423+
DBUG_VOID_RETURN;
14141424
}
14151425
if (m_pcur_parts != NULL) {
14161426
m_prebuilt->pcur = &m_pcur_parts[m_pcur_map[part_id]];
@@ -1421,11 +1431,23 @@ ha_innopart::set_partition(
14211431
}
14221432
m_prebuilt->ins_node = m_ins_node_parts[part_id];
14231433
m_prebuilt->upd_node = m_upd_node_parts[part_id];
1434+
1435+
#ifdef UNIV_DEBUG
1436+
if (m_blob_heap_parts[part_id] != NULL) {
1437+
DBUG_PRINT("ha_innopart", ("validating blob_heap: %p",
1438+
m_blob_heap_parts[part_id]));
1439+
mem_heap_validate(m_blob_heap_parts[part_id]);
1440+
}
1441+
#endif
1442+
1443+
m_prebuilt->blob_heap = m_blob_heap_parts[part_id];
14241444
m_prebuilt->trx_id = m_trx_id_parts[part_id];
14251445
m_prebuilt->row_read_type = m_row_read_type_parts[part_id];
14261446
m_prebuilt->sql_stat_start = get_bit(m_sql_stat_start_parts, part_id);
14271447
m_prebuilt->table = m_part_share->get_table_part(part_id);
14281448
m_prebuilt->index = innopart_get_index(part_id, active_index);
1449+
1450+
DBUG_VOID_RETURN;
14291451
}
14301452

14311453
/** Update active partition.
@@ -1435,17 +1457,31 @@ void
14351457
ha_innopart::update_partition(
14361458
uint part_id)
14371459
{
1460+
DBUG_ENTER("ha_innopart::update_partition");
1461+
DBUG_PRINT("ha_innopart", ("partition id: %u", part_id));
1462+
14381463
if (part_id >= m_tot_parts) {
14391464
ut_ad(0);
1440-
return;
1465+
DBUG_VOID_RETURN;
14411466
}
14421467
m_ins_node_parts[part_id] = m_prebuilt->ins_node;
14431468
m_upd_node_parts[part_id] = m_prebuilt->upd_node;
1469+
1470+
#ifdef UNIV_DEBUG
1471+
if (m_prebuilt->blob_heap != NULL) {
1472+
DBUG_PRINT("ha_innopart", ("validating blob_heap: %p",
1473+
m_prebuilt->blob_heap));
1474+
mem_heap_validate(m_prebuilt->blob_heap);
1475+
}
1476+
#endif
1477+
1478+
m_blob_heap_parts[part_id] = m_prebuilt->blob_heap;
14441479
m_trx_id_parts[part_id] = m_prebuilt->trx_id;
14451480
m_row_read_type_parts[part_id] = m_prebuilt->row_read_type;
14461481
update_bit(m_sql_stat_start_parts, part_id,
14471482
m_prebuilt->sql_stat_start == 0 ? false : true);
14481483
m_last_part = part_id;
1484+
DBUG_VOID_RETURN;
14491485
}
14501486

14511487
/** Save currently highest auto increment value.
@@ -1640,13 +1676,15 @@ ha_innopart::index_end()
16401676
{
16411677
uint part_id = m_part_info->get_first_used_partition();
16421678
DBUG_ENTER("ha_innopart::index_end");
1679+
16431680
if (part_id == MY_BIT_NONE) {
16441681
/* Never initialized any index. */
16451682
DBUG_RETURN(0);
16461683
}
16471684
if (m_ordered) {
16481685
destroy_record_priority_queue();
16491686
}
1687+
16501688
DBUG_RETURN(ha_innobase::index_end());
16511689
}
16521690

@@ -1943,10 +1981,13 @@ ha_innopart::index_first_in_part(
19431981
uchar* record)
19441982
{
19451983
int error;
1984+
DBUG_ENTER("ha_innopart::index_first_in_part");
1985+
19461986
set_partition(part);
19471987
error = ha_innobase::index_first(record);
19481988
update_partition(part);
1949-
return(error);
1989+
1990+
DBUG_RETURN(error);
19501991
}
19511992

19521993
/** Return next record in index from a partition.
@@ -1958,7 +1999,11 @@ ha_innopart::index_next_in_part(
19581999
uint part,
19592000
uchar* record)
19602001
{
2002+
DBUG_ENTER("ha_innopart::index_next_in_part");
2003+
19612004
int error;
2005+
2006+
clear_blob_heap_part(part);
19622007
set_partition(part);
19632008
error = ha_innobase::index_next(record);
19642009
update_partition(part);
@@ -1980,7 +2025,7 @@ ha_innopart::index_next_in_part(
19802025
m_prebuilt->n_rows_fetched = 0;
19812026
}
19822027

1983-
return(error);
2028+
DBUG_RETURN(error);
19842029
}
19852030

19862031
/** Return next same record in index from a partition.
@@ -1999,6 +2044,9 @@ ha_innopart::index_next_same_in_part(
19992044
uint length)
20002045
{
20012046
int error;
2047+
2048+
clear_blob_heap_part(part);
2049+
20022050
set_partition(part);
20032051
error = ha_innobase::index_next_same(record, key, length);
20042052
update_partition(part);
@@ -2015,6 +2063,7 @@ ha_innopart::index_last_in_part(
20152063
uchar* record)
20162064
{
20172065
int error;
2066+
20182067
set_partition(part);
20192068
error = ha_innobase::index_last(record);
20202069
update_partition(part);
@@ -2031,6 +2080,9 @@ ha_innopart::index_prev_in_part(
20312080
uchar* record)
20322081
{
20332082
int error;
2083+
2084+
clear_blob_heap_part(part);
2085+
20342086
set_partition(part);
20352087
error = ha_innobase::index_prev(record);
20362088
update_partition(part);
@@ -2072,6 +2124,7 @@ ha_innopart::index_read_map_in_part(
20722124
enum ha_rkey_function find_flag)
20732125
{
20742126
int error;
2127+
20752128
set_partition(part);
20762129
error = ha_innobase::index_read_map(
20772130
record,
@@ -2102,6 +2155,7 @@ ha_innopart::index_read_idx_map_in_part(
21022155
enum ha_rkey_function find_flag)
21032156
{
21042157
int error;
2158+
21052159
set_partition(part);
21062160
error = ha_innobase::index_read_idx_map(
21072161
record,
@@ -2200,6 +2254,8 @@ ha_innopart::read_range_next_in_part(
22002254
{
22012255
int error;
22022256
uchar* read_record = record;
2257+
2258+
clear_blob_heap_part(part);
22032259
set_partition(part);
22042260
if (read_record == NULL) {
22052261
read_record = table->record[0];
@@ -2253,6 +2309,8 @@ ha_innopart::rnd_init_in_part(
22532309
{
22542310
int err;
22552311

2312+
clear_blob_heap_part(part_id);
2313+
22562314
if (m_prebuilt->clust_index_was_generated) {
22572315
err = change_active_index(part_id, MAX_KEY);
22582316
} else {
@@ -2280,6 +2338,9 @@ ha_innopart::rnd_end_in_part(
22802338
uint part_id,
22812339
bool scan)
22822340
{
2341+
2342+
m_prebuilt->blob_heap = NULL;
2343+
22832344
return(index_end());
22842345
}
22852346

@@ -2298,6 +2359,7 @@ ha_innopart::rnd_next_in_part(
22982359

22992360
DBUG_ENTER("ha_innopart::rnd_next_in_part");
23002361

2362+
clear_blob_heap_part(part_id);
23012363
set_partition(part_id);
23022364
if (m_start_of_scan) {
23032365
error = ha_innobase::index_first(buf);
@@ -2338,6 +2400,7 @@ ha_innopart::rnd_pos(
23382400

23392401
/* Restore used partition. */
23402402
part_id = uint2korr(pos);
2403+
23412404
set_partition(part_id);
23422405

23432406
/* Note that we assume the length of the row reference is fixed
@@ -4166,6 +4229,96 @@ ha_innopart::write_row_in_new_part(
41664229
DBUG_RETURN(result);
41674230
}
41684231

4232+
/** Allocate the array to hold blob heaps for all partitions */
4233+
mem_heap_t**
4234+
ha_innopart::alloc_blob_heap_array()
4235+
{
4236+
DBUG_ENTER("ha_innopart::alloc_blob_heap_array");
4237+
4238+
const ulint len = sizeof(mem_heap_t*) * m_tot_parts;
4239+
m_blob_heap_parts = static_cast<mem_heap_t**>(
4240+
ut_malloc(len, mem_key_partitioning));
4241+
if (m_blob_heap_parts == NULL) {
4242+
DBUG_RETURN(NULL);
4243+
}
4244+
memset(m_blob_heap_parts, 0, len);
4245+
4246+
DBUG_RETURN(m_blob_heap_parts);
4247+
}
4248+
4249+
/** Free the array that holds blob heaps for all partitions */
4250+
void
4251+
ha_innopart::free_blob_heap_array()
4252+
{
4253+
DBUG_ENTER("ha_innopart::free_blob_heap_array");
4254+
4255+
if (m_blob_heap_parts != NULL) {
4256+
clear_blob_heaps();
4257+
ut_free(m_blob_heap_parts);
4258+
m_blob_heap_parts = NULL;
4259+
}
4260+
4261+
DBUG_VOID_RETURN;
4262+
}
4263+
4264+
/** Clear the blob heap for the given partition */
4265+
void
4266+
ha_innopart::clear_blob_heap_part(uint part_id)
4267+
{
4268+
DBUG_ENTER("ha_innopart::clear_blob_heap_part");
4269+
DBUG_PRINT("ha_innopart", ("partition id: %u", part_id));
4270+
4271+
4272+
if (m_blob_heap_parts != NULL
4273+
&& m_blob_heap_parts[part_id] != NULL) {
4274+
4275+
DBUG_PRINT("ha_innopart", ("freeing blob_heap: %p",
4276+
m_blob_heap_parts[part_id]));
4277+
mem_heap_free(m_blob_heap_parts[part_id]);
4278+
m_blob_heap_parts[part_id] = NULL;
4279+
4280+
}
4281+
4282+
m_prebuilt->blob_heap = NULL;
4283+
4284+
DBUG_VOID_RETURN;
4285+
}
4286+
4287+
void
4288+
ha_innopart::clear_blob_heaps()
4289+
{
4290+
DBUG_ENTER("ha_innopart::clear_blob_heaps");
4291+
4292+
if (m_blob_heap_parts == NULL) {
4293+
DBUG_VOID_RETURN;
4294+
}
4295+
4296+
for (uint i = 0; i < m_tot_parts; i++) {
4297+
if (m_blob_heap_parts[i] != NULL) {
4298+
DBUG_PRINT("ha_innopart", ("freeing blob_heap: %p",
4299+
m_blob_heap_parts[i]));
4300+
mem_heap_free(m_blob_heap_parts[i]);
4301+
m_blob_heap_parts[i] = NULL;
4302+
}
4303+
}
4304+
4305+
m_prebuilt->blob_heap = NULL;
4306+
4307+
DBUG_VOID_RETURN;
4308+
}
4309+
4310+
/** Reset state of file to after 'open'. This function is called
4311+
after every statement for all tables used by that statement. */
4312+
int
4313+
ha_innopart::reset()
4314+
{
4315+
DBUG_ENTER("ha_innopart::reset");
4316+
4317+
clear_blob_heaps();
4318+
4319+
DBUG_RETURN(ha_innobase::reset());
4320+
}
4321+
41694322
/****************************************************************************
41704323
* DS-MRR implementation
41714324
***************************************************************************/

0 commit comments

Comments
 (0)