Skip to content

Commit 33023ba

Browse files
committed
MDEV-30732 : wsrep_store_key_val_for_row() may invoke memcpy() on nullptr
Problem was that row_mysql_read_blob_ref can return NULL in case when blob datatype is used in a key and its real value is NULL. This NULL pointer is then used in memcpy function in wsrep_store_key_val_for_row. However, memcpy is defined so that argument 2 must not be NULL. Fixed by adding conditions before memcpy functions so that argument 2 is always non NULL.
1 parent 990b444 commit 33023ba

File tree

3 files changed

+92
-17
lines changed

3 files changed

+92
-17
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
connection node_2;
2+
connection node_1;
3+
SET GLOBAL sql_mode=0;
4+
SET sql_mode=DEFAULT;
5+
CREATE TABLE t (c INT,c2 BLOB NOT NULL,KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT;
6+
INSERT INTO t (c) VALUES (1),(1),(1),(1),(1);
7+
Warnings:
8+
Warning 1364 Field 'c2' doesn't have a default value
9+
SELECT * FROM t;
10+
c c2
11+
1
12+
1
13+
1
14+
1
15+
1
16+
DROP TABLE t;
17+
CREATE TABLE t (c INT,c2 VARCHAR(270) NOT NULL,KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT;
18+
INSERT INTO t (c) VALUES (1),(1),(1),(1),(1);
19+
Warnings:
20+
Warning 1364 Field 'c2' doesn't have a default value
21+
SELECT * FROM t;
22+
c c2
23+
1
24+
1
25+
1
26+
1
27+
1
28+
DROP TABLE t;
29+
CREATE TABLE t (c INT,c2 CHAR(80) NOT NULL,KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT;
30+
INSERT INTO t (c) VALUES (1),(1),(1),(1),(1);
31+
Warnings:
32+
Warning 1364 Field 'c2' doesn't have a default value
33+
SELECT * FROM t;
34+
c c2
35+
1
36+
1
37+
1
38+
1
39+
1
40+
DROP TABLE t;
41+
SET GLOBAL sql_mode=DEFAULT;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--source include/galera_cluster.inc
2+
3+
SET GLOBAL sql_mode=0;
4+
SET sql_mode=DEFAULT;
5+
CREATE TABLE t (c INT,c2 BLOB NOT NULL,KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT;
6+
INSERT INTO t (c) VALUES (1),(1),(1),(1),(1);
7+
SELECT * FROM t;
8+
DROP TABLE t;
9+
CREATE TABLE t (c INT,c2 VARCHAR(270) NOT NULL,KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT;
10+
INSERT INTO t (c) VALUES (1),(1),(1),(1),(1);
11+
SELECT * FROM t;
12+
DROP TABLE t;
13+
CREATE TABLE t (c INT,c2 CHAR(80) NOT NULL,KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT;
14+
INSERT INTO t (c) VALUES (1),(1),(1),(1),(1);
15+
SELECT * FROM t;
16+
DROP TABLE t;
17+
18+
SET GLOBAL sql_mode=DEFAULT;

storage/innobase/handler/ha_innodb.cc

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6675,8 +6675,9 @@ wsrep_store_key_val_for_row(
66756675
*key_is_null = true;
66766676

66776677
for (; key_part != end; key_part++) {
6678-
uchar sorted[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'};
6678+
uchar sorted[REC_VERSION_56_MAX_INDEX_COL_LEN];
66796679
bool part_is_null = false;
6680+
memset(sorted, 0, sizeof(sorted));
66806681

66816682
if (key_part->null_bit) {
66826683
if (buff_space > 0) {
@@ -6755,13 +6756,17 @@ wsrep_store_key_val_for_row(
67556756
/* cannot exceed max column lenght either, we may need to truncate
67566757
the stored value: */
67576758
if (true_len > sizeof(sorted)) {
6758-
true_len = sizeof(sorted);
6759+
true_len = sizeof(sorted);
67596760
}
67606761

6761-
memcpy(sorted, data, true_len);
6762-
true_len = wsrep_innobase_mysql_sort(
6763-
mysql_type, cs->number, sorted, true_len,
6764-
REC_VERSION_56_MAX_INDEX_COL_LEN);
6762+
ut_ad(data || (data == nullptr && true_len == 0));
6763+
if (data) {
6764+
memcpy(sorted, data, true_len);
6765+
6766+
true_len = wsrep_innobase_mysql_sort(
6767+
mysql_type, cs->number, sorted, true_len,
6768+
REC_VERSION_56_MAX_INDEX_COL_LEN);
6769+
}
67656770
if (wsrep_protocol_version > 1) {
67666771
/* Note that we always reserve the maximum possible
67676772
length of the true VARCHAR in the key value, though
@@ -6774,7 +6779,7 @@ wsrep_store_key_val_for_row(
67746779
wsrep_thd_query(thd));
67756780
true_len = buff_space;
67766781
}
6777-
memcpy(buff, sorted, true_len);
6782+
memcpy(buff, sorted, true_len);
67786783
buff += true_len;
67796784
buff_space -= true_len;
67806785
} else {
@@ -6846,11 +6851,14 @@ wsrep_store_key_val_for_row(
68466851
true_len = key_len;
68476852
}
68486853

6849-
memcpy(sorted, blob_data, true_len);
6850-
true_len = wsrep_innobase_mysql_sort(
6851-
mysql_type, cs->number, sorted, true_len,
6852-
REC_VERSION_56_MAX_INDEX_COL_LEN);
6853-
6854+
ut_ad(blob_data || (blob_data == nullptr && true_len == 0));
6855+
if (blob_data) {
6856+
memcpy(sorted, blob_data, true_len);
6857+
6858+
true_len = wsrep_innobase_mysql_sort(
6859+
mysql_type, cs->number, sorted, true_len,
6860+
REC_VERSION_56_MAX_INDEX_COL_LEN);
6861+
}
68546862

68556863
/* Note that we always reserve the maximum possible
68566864
length of the BLOB prefix in the key value. */
@@ -6926,10 +6934,15 @@ wsrep_store_key_val_for_row(
69266934
cs->mbmaxlen),
69276935
&error);
69286936
}
6929-
memcpy(sorted, src_start, true_len);
6930-
true_len = wsrep_innobase_mysql_sort(
6931-
mysql_type, cs->number, sorted, true_len,
6932-
REC_VERSION_56_MAX_INDEX_COL_LEN);
6937+
6938+
ut_ad(src_start || (src_start == nullptr && true_len == 0));
6939+
if (src_start) {
6940+
memcpy(sorted, src_start, true_len);
6941+
6942+
true_len = wsrep_innobase_mysql_sort(
6943+
mysql_type, cs->number, sorted, true_len,
6944+
REC_VERSION_56_MAX_INDEX_COL_LEN);
6945+
}
69336946

69346947
if (true_len > buff_space) {
69356948
fprintf (stderr,
@@ -6939,7 +6952,10 @@ wsrep_store_key_val_for_row(
69396952
}
69406953
memcpy(buff, sorted, true_len);
69416954
} else {
6942-
memcpy(buff, src_start, true_len);
6955+
ut_ad(src_start || (src_start == nullptr && true_len == 0));
6956+
if (src_start) {
6957+
memcpy(buff, src_start, true_len);
6958+
}
69436959
}
69446960
buff += true_len;
69456961
buff_space -= true_len;

0 commit comments

Comments
 (0)