#At file:///home/bar/mysql-bzr/mysql-6.0-b34021/
2772 Alexander Barkov 2008-12-04
Bug#34021 Character sets: crash if concatenate utf32 and number
Problem: When inserting a CONCAT between an UTF32 string
and a number into an UTF32 column, mysqld could crashed.
That happened was:
- Item_num::safe_charset_converter() returned wrong length,
which is not divisible by mbminlen=4.
- As a result, Item_func_concat() returned wrong length.
- Then this call stack happened:
Field_string::store() ->
well_formed_copy_nchars() ->
to_cs->cset->well_formed_len() ->
my_well_formed_len_utf32()
- The latter call crashed on assert:
DBUG_ASSERT((length % 4) == 0);
Fix: Item_num_safe_charset_converter() now adds leading
zeros if str_val() returned a string with length not
divisible by mbminlen.
modified:
mysql-test/r/ctype_utf32.result
mysql-test/t/ctype_utf32.test
sql/item.cc
=== modified file 'mysql-test/r/ctype_utf32.result'
--- a/mysql-test/r/ctype_utf32.result 2008-07-24 12:15:24 +0000
+++ b/mysql-test/r/ctype_utf32.result 2008-12-04 13:24:28 +0000
@@ -1411,3 +1411,40 @@ hex(weight_string(s1, 4, 2, 0))
DROP TABLE t1;
SET max_sort_length=DEFAULT;
SET NAMES latin1;
+drop table if exists t1;
+Warnings:
+Note 1051 Unknown table 't1'
+create table t1 (s1 char(5) character set utf32);
+insert into t1 values ('a');
+insert into t1 select concat(s1, 1) from t1;
+select hex(s1) from t1;
+hex(s1)
+00000061
+0000006100000031
+drop table t1;
+drop table if exists t1;
+Warnings:
+Note 1051 Unknown table 't1'
+create table t1 (s1 char(5) character set utf32);
+insert into t1 values ('a');
+insert into t1 select concat(s1, 0.1) from t1;
+Warnings:
+Warning 1366 Incorrect string value: '\x00\x30\x2E\x31' for column 's1' at row 1
+select hex(s1) from t1;
+hex(s1)
+00000061
+00000061
+drop table t1;
+drop table if exists t1;
+Warnings:
+Note 1051 Unknown table 't1'
+create table t1 (s1 char(5) character set utf32);
+insert into t1 values ('a');
+insert into t1 select concat(s1, 1e-1) from t1;
+Warnings:
+Warning 1366 Incorrect string value: '\x00\x30\x2E\x31' for column 's1' at row 1
+select hex(s1) from t1;
+hex(s1)
+00000061
+00000061
+drop table t1;
=== modified file 'mysql-test/t/ctype_utf32.test'
--- a/mysql-test/t/ctype_utf32.test 2008-07-24 12:15:24 +0000
+++ b/mysql-test/t/ctype_utf32.test 2008-12-04 13:24:28 +0000
@@ -788,3 +788,32 @@ SELECT hex(weight_string(s1, 4, 2, 0)) F
DROP TABLE t1;
SET max_sort_length=DEFAULT;
SET NAMES latin1;
+
+#
+# Bug#34021 Character sets: crash if concatenate utf32 and number
+#
+
+# Test concat with INT
+drop table if exists t1;
+create table t1 (s1 char(5) character set utf32);
+insert into t1 values ('a');
+insert into t1 select concat(s1, 1) from t1;
+select hex(s1) from t1;
+drop table t1;
+
+# Test concat with DECIMAL (warning is expected)
+drop table if exists t1;
+create table t1 (s1 char(5) character set utf32);
+insert into t1 values ('a');
+insert into t1 select concat(s1, 0.1) from t1;
+select hex(s1) from t1;
+drop table t1;
+
+# Test concat with FLOAT (warning is expected)
+drop table if exists t1;
+create table t1 (s1 char(5) character set utf32);
+insert into t1 values ('a');
+insert into t1 select concat(s1, 1e-1) from t1;
+select hex(s1) from t1;
+drop table t1;
+
=== modified file 'sql/item.cc'
--- a/sql/item.cc 2008-11-06 18:39:27 +0000
+++ b/sql/item.cc 2008-12-04 13:24:28 +0000
@@ -774,14 +774,40 @@ Item *Item::safe_charset_converter(CHARS
We cannot use generic Item::safe_charset_converter(), because
the latter returns a non-fixed Item, so val_str() crashes afterwards.
Override Item_num method, to return a fixed item.
+
+ If Item_num's length is not divisible to mbmaxlen,
+ then value is left padded with zero bytes 0x00.
*/
Item *Item_num::safe_charset_converter(CHARSET_INFO *tocs)
{
Item_string *conv;
+ char zeros[4]; /* This must be before "buf" */
char buf[64];
String *s, tmp(buf, sizeof(buf), &my_charset_bin);
s= val_str(&tmp);
- if ((conv= new Item_string(s->ptr(), s->length(), s->charset())))
+ uint32 nzeros= tocs->mbmaxlen - (s->length() % tocs->mbmaxlen);
+
+ if (nzeros)
+ {
+ /* Clear zeros's memory if leading 0x00 bytes are to be padded */
+ memset(zeros, 0, sizeof(zeros));
+ /* Make sure that "zeros" is big enough */
+ DBUG_ASSERT(tocs->mbmaxlen <= sizeof(zeros));
+ /*
+ Make sure val_str returns pointer to "buf".
+ That should be always true, according to
+ Item_num::val_str() implementation.
+ */
+ DBUG_ASSERT(s->ptr() == (const char*) &buf);
+ }
+
+
+ /*
+ TODO for 6.1: remove this trick with zeros
+ when WL#2649 "Number-to-string conversions" is done.
+ */
+ if ((conv= new Item_string(s->ptr() - nzeros,
+ s->length() + nzeros, s->charset())))
{
conv->str_value.copy();
conv->str_value.mark_as_const();
| Thread |
|---|
| • bzr commit into mysql-6.0-bugteam branch (bar:2772) Bug#34021 | Alexander Barkov | 4 Dec |