| Bug #44886 | SIGSEGV in test_if_skip_sort_order() - uninitialized variable used as subscript | ||
|---|---|---|---|
| Submitted: | 14 May 2009 20:08 | Modified: | 29 Jun 2009 19:48 | 
| Reporter: | Guillaume Giroux | Email Updates: | |
| Status: | Closed | Impact on me: | |
| Category: | MySQL Server: Optimizer | Severity: | S2 (Serious) | 
| Version: | 5.1.34, 5.1, 6.0 bzr | OS: | Linux (CentOS 5.2 x86_64) | 
| Assigned to: | Gleb Shchepa | CPU Architecture: | Any | 
| Tags: | Contribution, regression, SIGSEGV | ||
   [15 May 2009 5:47]
   Sveta Smirnova        
  Thank you for the report.
Backtrace in my environment:
Thread 1 (process 19545):
#0  0x002ce402 in __kernel_vsyscall ()
#1  0x0046264f in pthread_kill () from /lib/libpthread.so.0
#2  0x085a7585 in my_write_core (sig=11) at stacktrace.c:310
#3  0x0824d392 in handle_segfault (sig=11) at mysqld.cc:2536
#4  <signal handler called>
#5  0x082df93c in test_if_skip_sort_order (tab=0x97124b0, order=0x970ed18, select_limit=2, no_changes=false, map=0x96ffb0c) at sql_select.cc:13141
#6  0x082e9e76 in JOIN::optimize (this=0x970edc8) at sql_select.cc:1360
#7  0x082efda1 in mysql_select (thd=0x96a8d38, rref_pointer_array=0x96aa1d0, tables=0x9723cd8, wild_num=0, fields=@0x96aa16c, conds=0x970eb88, og_num=1, order=0x0, group=0x970ed18, having=0x0, 
    proc_param=0x0, select_options=2147764736, result=0x970edb0, unit=0x96a9e68, select_lex=0x96aa0d8) at sql_select.cc:2364
#8  0x082f017f in handle_select (thd=0x96a8d38, lex=0x96a9e0c, result=0x970edb0, setup_tables_done_option=0) at sql_select.cc:268
#9  0x0825c757 in execute_sqlcom_select (thd=0x96a8d38, all_tables=0x9723cd8) at sql_parse.cc:5009
#10 0x08262a87 in mysql_execute_command (thd=0x96a8d38) at sql_parse.cc:2211
#11 0x0826c258 in mysql_parse (thd=0x96a8d38, 
    inBuf=0x9723960 "SELECT  FOO.FOO_ID\nFROM    FOO_BAR\nINNER JOIN FOO ON (FOO.FOO_ID = FOO_BAR.FOO_ID)\nINNER JOIN BAR ON (BAR.FOO_ID = FOO.FOO_ID AND (BAR.BAR_ID = FOO_BAR.BAR_ID OR\nBAR.STATUS & 1))\nLEFT JOIN BAZ ON (BAZ"..., length=302, found_semicolon=0xb2b992fc) at sql_parse.cc:5929
#12 0x0826ce94 in dispatch_command (command=COM_QUERY, thd=0x96a8d38, 
    packet=0x96eddb1 "SELECT  FOO.FOO_ID\nFROM    FOO_BAR\nINNER JOIN FOO ON (FOO.FOO_ID = FOO_BAR.FOO_ID)\nINNER JOIN BAR ON (BAR.FOO_ID = FOO.FOO_ID AND (BAR.BAR_ID = FOO_BAR.BAR_ID OR\nBAR.STATUS & 1))\nLEFT JOIN BAZ ON (BAZ"..., packet_length=302) at sql_parse.cc:1216
#13 0x0826e0b2 in do_command (thd=0x96a8d38) at sql_parse.cc:857
#14 0x0825a831 in handle_one_connection (arg=0x96a8d38) at sql_connect.cc:1115
#15 0x0045fbd4 in start_thread () from /lib/libpthread.so.0
#16 0x003b74fe in clone () from /lib/libc.so.6
 
   [15 May 2009 5:50]
   Sveta Smirnova        
  There is similar bug #37868
   [18 May 2009 19:35]
   Sveta Smirnova        
  Bug does not exist in versions 4.1 and 5.0
   [5 Jun 2009 14:39]
   Gleb Shchepa        
  This bug was introduced by the small part of a bug #31001 fix: @@ -12353,6 +12353,12 @@ static int test_if_order_by_key(ORDER *o for (; const_key_parts & 1 ; const_key_parts>>= 1) key_part++; + /* + The primary and secondary key parts were all const (i.e. there's + one row). The sorting doesn't matter. + */ + if (key_part == key_part_end && reverse == 0) + DBUG_RETURN(1); } else DBUG_RETURN(0); This new code fragment returns value of 1 ("key is ok"), but it doesn't update the used_key_parts output parameter of the test_if_order_by_key function. That causes a crash.
   [5 Jun 2009 19:26]
   Bugs System        
  A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/75737 2929 Gleb Shchepa 2009-06-06 Bug #44886: SIGSEGV in test_if_skip_sort_order() - uninitialized variable used as subscript Grouping select from a "constant" InnoDB table (a table of a single row) joined with other tables caused a crash. @ mysql-test/r/innodb_mysql.result Added test case for bug bug #44886. @ mysql-test/t/innodb_mysql.test Added test case for bug bug #44886. @ sql/sql_select.cc Bug #44886: SIGSEGV in test_if_skip_sort_order() - uninitialized variable used as subscript 1. The test_if_order_by_key function returned unitialized used_key_parts parameter in case of a "constant" InnoDB table. Calling function uses this parameter values as an array index, thus sometimes it caused a crash. The test_if_order_by_key function has been modified to set used_key_parts to 0 (no need for ordering). 2. The test_if_skip_sort_order function has been modified to accept zero used_key_parts value and to prevent an array access by negative index.
   [16 Jun 2009 11:04]
   Bugs System        
  Pushed into 5.1.36 (revid:joro@sun.com-20090616102155-3zhezogudt4uxdyn) (version source revid:gshchepa@mysql.com-20090607204053-0kai6dlgdwdbohlv) (merge vers: 5.1.36) (pib:6)
   [17 Jun 2009 19:25]
   Bugs System        
  Pushed into 5.4.4-alpha (revid:alik@sun.com-20090616183122-chjzbaa30qopdra9) (version source revid:gshchepa@mysql.com-20090607205014-t64c0ktv7i58p62d) (merge vers: 6.0.12-alpha) (pib:11)
   [29 Jun 2009 19:48]
   Paul DuBois        
  Noted in 5.1.36, 5.4.4 changelogs. GROUP BY on a constant (single-row) InnoDB table joined to other tables caused a server crash.
   [12 Aug 2009 22:25]
   Paul DuBois        
  Noted in 5.4.2 changelog because next 5.4 version will be 5.4.2 and not 5.4.4.
   [15 Aug 2009 1:42]
   Paul DuBois        
  Ignore previous comment about 5.4.2.
   [26 Aug 2009 13:46]
   Bugs System        
  Pushed into 5.1.37-ndb-7.0.8 (revid:jonas@mysql.com-20090826132541-yablppc59e3yb54l) (version source revid:jonas@mysql.com-20090826132541-yablppc59e3yb54l) (merge vers: 5.1.37-ndb-7.0.8) (pib:11)
   [26 Aug 2009 13:46]
   Bugs System        
  Pushed into 5.1.37-ndb-6.3.27 (revid:jonas@mysql.com-20090826105955-bkj027t47gfbamnc) (version source revid:jonas@mysql.com-20090826105955-bkj027t47gfbamnc) (merge vers: 5.1.37-ndb-6.3.27) (pib:11)
   [26 Aug 2009 13:48]
   Bugs System        
  Pushed into 5.1.37-ndb-6.2.19 (revid:jonas@mysql.com-20090825194404-37rtosk049t9koc4) (version source revid:jonas@mysql.com-20090825194404-37rtosk049t9koc4) (merge vers: 5.1.37-ndb-6.2.19) (pib:11)
   [27 Aug 2009 16:33]
   Bugs System        
  Pushed into 5.1.35-ndb-7.1.0 (revid:magnus.blaudd@sun.com-20090827163030-6o3kk6r2oua159hr) (version source revid:jonas@mysql.com-20090826132541-yablppc59e3yb54l) (merge vers: 5.1.37-ndb-7.0.8) (pib:11)
   [7 Oct 2009 19:13]
   Paul DuBois        
  The 5.4 fix has been pushed to 5.4.2.

Description: crash with SIGSEGV in sql_select.cc::test_if_skip_sort_order() At line 13129 rec_per_key= keyinfo->rec_per_key[used_key_parts-1]; used_key_parts can be used uninitialized, thus crashing or reading random memory. used_key_parts is initialized by test_if_order_by_key(), but this one has many exit points that won't assign *used_key_parts. The test case demonstrates it quite clearly. How to repeat: 100% reproducible test case: drop table IF EXISTS FOO; CREATE TABLE `FOO` ( `FOO_ID` int(10) unsigned NOT NULL AUTO_INCREMENT, `A` int(20) DEFAULT NULL, PRIMARY KEY (`FOO_ID`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; insert into FOO VALUES(NULL,1); insert into FOO VALUES(NULL,2); drop table IF EXISTS BAR; CREATE TABLE `BAR` ( `BAR_ID` int(10) unsigned NOT NULL AUTO_INCREMENT, `FOO_ID` int(10) unsigned NOT NULL DEFAULT '0', `TYPE` smallint(5) unsigned NOT NULL DEFAULT '1', `STATUS` bigint(20) unsigned DEFAULT '0', PRIMARY KEY (`BAR_ID`), KEY `IDX_FOO` (`FOO_ID`,`TYPE`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; insert into BAR VALUES(NULL,1,1,0); insert into BAR VALUES(NULL,2,1,0); drop table IF EXISTS BAZ; CREATE TABLE `BAZ` ( `BAZ_ID` int(10) unsigned NOT NULL AUTO_INCREMENT, `FOO_ID` int(10) unsigned NOT NULL DEFAULT '0', `BAR_ID` int(10) unsigned NOT NULL, `BAZ_TAG` varchar(100) DEFAULT NULL, PRIMARY KEY (`BAZ_ID`), UNIQUE KEY `UDX_FOO_BAR` (`FOO_ID`,`BAR_ID`), KEY `IDX_BAZTAG` (`BAZ_TAG`) ) ENGINE=InnoDB CHARSET=latin1; insert into BAZ values(NULL,1,1,'foo@bar.com'); insert into BAZ values(NULL,2,1,'foo@bar.com'); DROP TABLE IF EXISTS FOO_BAR; CREATE TABLE `FOO_BAR` ( `FOO_ID` int(10) unsigned DEFAULT '0', `BAR_ID` int(10) unsigned DEFAULT '0' ) ENGINE=MyISAM CHARSET=latin1; # Does not crash with ENGINE=InnoDB INSERT INTO FOO_BAR VALUES (1, 1); SELECT FOO.FOO_ID FROM FOO_BAR INNER JOIN FOO ON (FOO.FOO_ID = FOO_BAR.FOO_ID) INNER JOIN BAR ON (BAR.FOO_ID = FOO.FOO_ID AND (BAR.BAR_ID = FOO_BAR.BAR_ID OR BAR.STATUS & 1)) LEFT JOIN BAZ ON (BAZ.BAR_ID = BAR.BAR_ID AND BAZ_TAG = 'foo@bar.com') WHERE BAZ_TAG = 'foo@bar.com' GROUP BY BAR.BAR_ID; Suggested fix: --- mysql-5.1.34/sql/sql_select.cc.ori 2009-05-14 09:23:16.000000000 -0400 +++ mysql-5.1.34/sql/sql_select.cc 2009-05-14 09:23:16.000000000 -0400 @@ -12912,7 +12912,7 @@ int ref_key; uint ref_key_parts; int order_direction; - uint used_key_parts; + uint used_key_parts= 0; TABLE *table=tab->table; SQL_SELECT *select=tab->select; key_map usable_keys; @@ -13124,7 +13124,7 @@ KEY *keyinfo= tab->table->key_info+nr; if (select_limit == HA_POS_ERROR) select_limit= table_records; - if (group) + if (group && used_key_parts) { rec_per_key= keyinfo->rec_per_key[used_key_parts-1]; set_if_bigger(rec_per_key, 1);