Commit 916245f9 authored by unknown's avatar unknown
Browse files

Bug#27079 Crash while grouping empty ucs2 strings

Problem: GROUP BY on empty ucs2 strings crashed server.
Reason: sometimes mi_unique_hash() is executed with
ptr=null and length=0, which means "empty string".
The branch of code handling UCS2 character set
was not safe against ptr=null and fell into and
endless loop even if length=0 because of poiter
arithmetic overflow.
Fix: adding special check for length=0 to avoid pointer arithmetic
overflow.


mysql-test/r/ctype_uca.result:
  Adding test case
mysql-test/t/ctype_uca.test:
  Adding test case
strings/ctype-uca.c:
  Fix my_uca_scanner_init_ucs2 to be safe against
  strings with length=0 and ptr=0.
parent 685d21b7
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -2654,3 +2654,12 @@ ii 2 ii 2 İİ 4
İİ	4	ii	2	İİ	4
II	2	ıı	4	II	2
DROP TABLE t1;
CREATE TABLE t1 (
c1 text character set ucs2 collate ucs2_polish_ci NOT NULL
) ENGINE=MyISAM;
insert into t1 values (''),('a');
SELECT COUNT(*), c1 FROM t1 GROUP BY c1;
COUNT(*)	c1
1	
1	a
DROP TABLE IF EXISTS t1;
+10 −0
Original line number Diff line number Diff line
@@ -475,3 +475,13 @@ ALTER TABLE t1 MODIFY a VARCHAR(30) character set utf8 collate utf8_turkish_ci;
SELECT a, length(a) la, @l:=lower(a) l, length(@l) ll, @u:=upper(a) u, length(@u) lu
FROM t1 ORDER BY id;
DROP TABLE t1;

#
# Bug #27079 Crash while grouping empty ucs2 strings
#
CREATE TABLE t1 (
 c1 text character set ucs2 collate ucs2_polish_ci NOT NULL
) ENGINE=MyISAM;
insert into t1 values (''),('a');
SELECT COUNT(*), c1 FROM t1 GROUP BY c1;
DROP TABLE IF EXISTS t1;
+27 −7
Original line number Diff line number Diff line
@@ -6744,7 +6744,7 @@ typedef struct my_uca_scanner_handler_st
  int (*next)(my_uca_scanner *scanner);
} my_uca_scanner_handler;

static uint16 nochar[]= {0};
static uint16 nochar[]= {0,0};


#ifdef HAVE_CHARSET_ucs2
@@ -6769,14 +6769,34 @@ static void my_uca_scanner_init_ucs2(my_uca_scanner *scanner,
                                     CHARSET_INFO *cs __attribute__((unused)),
                                     const uchar *str, uint length)
{
  /* Note, no needs to initialize scanner->wbeg */
  scanner->wbeg= nochar; 
  if (length)
  {
    scanner->sbeg= str;
    scanner->send= str + length - 2;
  scanner->wbeg= nochar; 
    scanner->uca_length= cs->sort_order;
    scanner->uca_weight= cs->sort_order_big;
    scanner->contractions= cs->contractions;
  }
  else
  {
    /*
      Sometimes this function is called with
      str=NULL and length=0, which should be
      considered as an empty string.
      
      The above initialization is unsafe for such cases,
      because scanner->send is initialized to (NULL-2), which is 0xFFFFFFFE.
      Then we fall into an endless loop in my_uca_scanner_next_ucs2().
      
      Do special initialization for the case when length=0.
      Initialize scanner->sbeg to an address greater than scanner->send.
      Next call of my_uca_scanner_next_ucs2() will correctly return with -1.
    */
    scanner->sbeg= (uchar*) &nochar[1];
    scanner->send= (uchar*) &nochar[0];
  }
}


/*