List:Commits« Previous MessageNext Message »
From:Alexander Barkov Date:December 4 2008 1:37pm
Subject:bzr commit into mysql-6.0-bugteam branch (bar:2772) Bug#34021
View as plain text  
#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#34021Alexander Barkov4 Dec