List:Commits« Previous MessageNext Message »
From:Alexander Barkov Date:April 7 2009 6:03am
Subject:bzr push into mysql-6.0-bugteam branch (bar:3183 to 3184) Bug#34021
View as plain text  
 3184 Alexander Barkov	2009-04-07
      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 crash.
              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 last 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:
      mysql-test/r/ctype_utf32.result
      mysql-test/t/ctype_utf32.test
      sql/item.cc
 3183 Alexander Barkov	2009-04-06
      #
      # Bug#24690 Stored functions: RETURNing UTF8 strings
      # do not return UTF8_UNICODE_CI collation
      #
            
            mysql-test/r/sp-ucs2.result:
            mysql-test/t/sp-ucs2.test:
            
              Adding tests
            
            sql/mysql_priv.h:
              Adding prototype
            
            sql/sp.cc
              Remember COLLATE clause for non-default collations
            
            sql/sql_parse.cc
              Adding new helper function
            
            sql/sql_yacc.yy
              - Allow "CHARACTER SET cs COLLATE cl" in
                SP parameters, RETURNS, DECLARE
              - Minor reorganization for "ASCII" and "UNICODE" 
                related rules, to make the code more readable,
                also to allow these aliases:
                * "VARCHAR(10) ASCII BINARY"   -> CHARACTER SET latin1 COLLATE latin1_bin 
                * "VARCHAR(10) BINARY ASCII"   -> CHARACTER SET latin1 COLLATE latin1_bin 
                * "VARCHAR(10) UNICODE BINARY" -> CHARACTER SET ucs2 COLLATE ucs2_bin 
                * "VARCHAR(10) BINARY UNICODE" -> CHARACTER SET ucs2 COLLATE ucs2_bin  
                Previously these four aliases returned the error
                "This version of MySQL does not yet support return value collation".
      
      Note:
      
               This patch allows  "VARCHAR(10) CHARACTER SET cs COLLATE cl"
               and the above four aliases.
            
               "VARCHAR(10) COLLATE cl" is still not allowed
               i.e. when COLLATE is given without CHARACTER SET.
               If we want to support this, we need an architecture decision
               which character set to use by default.

    modified:
      mysql-test/r/sp-ucs2.result
      mysql-test/t/sp-ucs2.test
      sql/mysql_priv.h
      sql/sp.cc
      sql/sql_parse.cc
      sql/sql_yacc.yy
=== 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	2009-04-07 06:01:03 +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	2009-04-07 06:01:03 +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	2009-04-01 11:13:40 +0000
+++ b/sql/item.cc	2009-04-07 06:01:03 +0000
@@ -784,14 +784,46 @@ 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)
 {
+  const size_t max_mbminlen= 4;
   Item_string *conv;
-  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())))
+  char buf[64 + max_mbminlen];
+  String tmp(buf + max_mbminlen, sizeof(buf) - max_mbminlen, &my_charset_bin);
+  String *s= val_str(&tmp);
+  uint32 nzeros= tocs->mbminlen - (s->length() % tocs->mbminlen);
+  
+  if (nzeros) 
+  {
+    /*
+      Need to left-pad some 0x00 bytes to return correct length.
+      Make sure that we reserved enough space for the leading 0x00 bytes,
+      then clear the leading bytes:
+      Note, int4store() should be a little bit faster than memset(buf,4).
+    */
+    DBUG_ASSERT(tocs->mbminlen <= max_mbminlen);
+    int4store(buf, 0);
+    
+    /*
+      Make sure val_str returns pointer to "buf",
+      (otherwise padding won't work).
+      That should be always true, according to
+      Item_num::val_str() implementation.
+    */
+    DBUG_ASSERT(s->ptr() == ((const char*) &buf) + 4);
+  }
+  
+  
+  /*
+    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();


Attachment: [text/bzr-bundle] bzr/bar@mysql.com-20090407060103-ghb9vaj2dbf996kv.bundle
Thread
bzr push into mysql-6.0-bugteam branch (bar:3183 to 3184) Bug#34021Alexander Barkov7 Apr