Skip to content

Commit 6400b19

Browse files
committed
MDEV-32249 strings/ctype-ucs2.c:2336: my_vsnprintf_utf32: Assertion `(n % 4) == 0' failed in my_vsnprintf_utf32 on INSERT
The crash inside my_vsnprintf_utf32() happened correctly, because the caller methods: Field_string::sql_rpl_type() Field_varstring::sql_rpl_type() mis-used the charset library and sent pure ASCII data to the virtual function snprintf() of a utf32 CHARSET_INFO. It was wrong to use Field::charset() in sql_rpl_type(). We're printing the metadata (the data type) here, not the column data. The string contraining the data type of a CHAR/VARCHAR column is a pure ASCII string. Fixing to use res->charset() to print, like all virtual implementations of sql_type() do. Review was done by Andrei Elkin. Thanks to Andrei for proposing MTR test improvents.
1 parent 3f1a256 commit 6400b19

File tree

3 files changed

+130
-2
lines changed

3 files changed

+130
-2
lines changed

mysql-test/suite/rpl/r/rpl_row_utf32.result

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,64 @@ connection master;
1919
INSERT INTO t1(c1) VALUES ('insert into t1');
2020
DROP TABLE t1;
2121
connection slave;
22+
#
23+
# MDEV-32249 strings/ctype-ucs2.c:2336: my_vsnprintf_utf32: Assertion `(n
24+
#
25+
#
26+
# Testing with VARCHAR
27+
#
28+
connection slave;
29+
include/stop_slave.inc
30+
SET GLOBAL SLAVE_TYPE_CONVERSIONS= '';
31+
include/start_slave.inc
32+
connection master;
33+
CREATE TABLE t1 (a INT);
34+
connection slave;
35+
ALTER TABLE t1 MODIFY a VARCHAR(1) CHARACTER SET utf32;
36+
connection master;
37+
INSERT INTO t1 VALUES (1);
38+
connection slave;
39+
include/wait_for_slave_sql_error.inc [errno=1677]
40+
SHOW CREATE TABLE t1;
41+
Table Create Table
42+
t1 CREATE TABLE `t1` (
43+
`a` varchar(1) CHARACTER SET utf32 COLLATE utf32_general_ci DEFAULT NULL
44+
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
45+
SELECT * FROM t1 ORDER BY a;
46+
a
47+
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
48+
START SLAVE;
49+
connection master;
50+
DROP TABLE t1;
51+
connection slave;
52+
#
53+
# Testing with CHAR
54+
#
55+
connection slave;
56+
include/stop_slave.inc
57+
SET GLOBAL SLAVE_TYPE_CONVERSIONS= '';
58+
include/start_slave.inc
59+
connection master;
60+
CREATE TABLE t1 (a INT);
61+
connection slave;
62+
ALTER TABLE t1 MODIFY a CHAR(1) CHARACTER SET utf32;
63+
connection master;
64+
INSERT INTO t1 VALUES (1);
65+
connection slave;
66+
include/wait_for_slave_sql_error.inc [errno=1677]
67+
SHOW CREATE TABLE t1;
68+
Table Create Table
69+
t1 CREATE TABLE `t1` (
70+
`a` char(1) CHARACTER SET utf32 COLLATE utf32_general_ci DEFAULT NULL
71+
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
72+
SELECT * FROM t1 ORDER BY a;
73+
a
74+
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
75+
START SLAVE;
76+
connection master;
77+
DROP TABLE t1;
78+
connection slave;
79+
connection slave;
2280
SET GLOBAL SLAVE_TYPE_CONVERSIONS= @saved_slave_type_conversions;
2381
include/stop_slave.inc
2482
include/start_slave.inc

mysql-test/suite/rpl/t/rpl_row_utf32.test

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,78 @@ DROP TABLE t1;
3434

3535
--sync_slave_with_master
3636

37+
--echo #
38+
--echo # MDEV-32249 strings/ctype-ucs2.c:2336: my_vsnprintf_utf32: Assertion `(n
39+
--echo #
40+
41+
--echo #
42+
--echo # Testing with VARCHAR
43+
--echo #
44+
45+
-- connection slave
46+
-- source include/stop_slave.inc
47+
SET GLOBAL SLAVE_TYPE_CONVERSIONS= '';
48+
-- source include/start_slave.inc
49+
50+
--connection master
51+
CREATE TABLE t1 (a INT);
52+
53+
--sync_slave_with_master
54+
ALTER TABLE t1 MODIFY a VARCHAR(1) CHARACTER SET utf32;
55+
56+
--connection master
57+
INSERT INTO t1 VALUES (1);
58+
59+
--connection slave
60+
# ER_SLAVE_CONVERSION_FAILED
61+
--let $slave_sql_errno= 1677
62+
--source include/wait_for_slave_sql_error.inc
63+
SHOW CREATE TABLE t1;
64+
SELECT * FROM t1 ORDER BY a;
65+
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
66+
START SLAVE;
67+
68+
--connection master
69+
DROP TABLE t1;
70+
--sync_slave_with_master
71+
72+
--echo #
73+
--echo # Testing with CHAR
74+
--echo #
75+
76+
-- connection slave
77+
-- source include/stop_slave.inc
78+
SET GLOBAL SLAVE_TYPE_CONVERSIONS= '';
79+
-- source include/start_slave.inc
80+
81+
--connection master
82+
CREATE TABLE t1 (a INT);
83+
84+
--sync_slave_with_master
85+
ALTER TABLE t1 MODIFY a CHAR(1) CHARACTER SET utf32;
86+
87+
--connection master
88+
INSERT INTO t1 VALUES (1);
89+
90+
--connection slave
91+
# ER_SLAVE_CONVERSION_FAILED
92+
--let $slave_sql_errno= 1677
93+
--source include/wait_for_slave_sql_error.inc
94+
SHOW CREATE TABLE t1;
95+
SELECT * FROM t1 ORDER BY a;
96+
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
97+
START SLAVE;
98+
99+
--connection master
100+
DROP TABLE t1;
101+
--sync_slave_with_master
102+
103+
37104
# assertion: the slave woul hit an/several assertions:
38105
# before and during slave conversion procedure
39106
# Now that is fixed, it wont.
40107

108+
-- connection slave
41109
SET GLOBAL SLAVE_TYPE_CONVERSIONS= @saved_slave_type_conversions;
42110
-- source include/stop_slave.inc
43111
-- source include/start_slave.inc

sql/field.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7487,9 +7487,10 @@ void Field_string::sql_type(String &res) const
74877487
*/
74887488
void Field_string::sql_rpl_type(String *res) const
74897489
{
7490-
CHARSET_INFO *cs=charset();
74917490
if (Field_string::has_charset())
74927491
{
7492+
CHARSET_INFO *cs= res->charset();
7493+
DBUG_ASSERT(cs->mbminlen == 1);
74937494
size_t length= cs->cset->snprintf(cs, (char*) res->ptr(),
74947495
res->alloced_length(),
74957496
"char(%u octets) character set %s",
@@ -7978,9 +7979,10 @@ void Field_varstring::sql_type(String &res) const
79787979
*/
79797980
void Field_varstring::sql_rpl_type(String *res) const
79807981
{
7981-
CHARSET_INFO *cs=charset();
79827982
if (Field_varstring::has_charset())
79837983
{
7984+
CHARSET_INFO *cs= res->charset();
7985+
DBUG_ASSERT(cs->mbminlen == 1);
79847986
size_t length= cs->cset->snprintf(cs, (char*) res->ptr(),
79857987
res->alloced_length(),
79867988
"varchar(%u octets) character set %s",

0 commit comments

Comments
 (0)