[mariadb] Server crashes on SQL select containing more group by and left join statements using innodb tables

Honza Horak hhorak at fedoraproject.org
Wed Mar 26 07:44:48 UTC 2014


commit 5b0ed2d4109f10e952f5e1c2abd1bab533a16c76
Author: Honza Horak <hhorak at redhat.com>
Date:   Wed Mar 12 11:38:27 2014 +0100

    Server crashes on SQL select containing more group by and left join statements using innodb tables
    
      Resolves: #1065676

 mariadb-rhbz1065676.patch |  386 +++++++++++++++++++++++++++++++++++++++++++++
 mariadb.spec              |    8 +-
 2 files changed, 393 insertions(+), 1 deletions(-)
---
diff --git a/mariadb-rhbz1065676.patch b/mariadb-rhbz1065676.patch
new file mode 100644
index 0000000..cdb6074
--- /dev/null
+++ b/mariadb-rhbz1065676.patch
@@ -0,0 +1,386 @@
+Backported from mariadb-5.5.37:
+https://mariadb.atlassian.net/browse/MDEV-5724
+https://bugzilla.redhat.com/show_bug.cgi?id=1065676
+
+diff -up mariadb-5.5.36/mysql-test/r/stack-crash.result.rhbz1065676 mariadb-5.5.36/mysql-test/r/stack-crash.result
+--- mariadb-5.5.36/mysql-test/r/stack-crash.result.rhbz1065676	2014-03-11 18:20:56.344327004 +0100
++++ mariadb-5.5.36/mysql-test/r/stack-crash.result	2014-03-11 18:20:56.344327004 +0100
+@@ -0,0 +1,93 @@
++drop table if exists t1,t2;
++Warnings:
++Note	1051	Unknown table 't1'
++Note	1051	Unknown table 't2'
++CREATE TABLE t1 (
++`sspo_id` int(11) NOT NULL AUTO_INCREMENT,
++`sspo_uid` int(11) NOT NULL DEFAULT '0',
++`sspo_type` varchar(1) NOT NULL DEFAULT 'P',
++`sspo_text` longtext NOT NULL,
++`sspo_image` varchar(255) NOT NULL,
++`sspo_source` int(11) NOT NULL DEFAULT '0',
++`sspo_event_name` varchar(255) NOT NULL DEFAULT '',
++`sspo_event_location` varchar(255) NOT NULL DEFAULT '',
++`sspo_event_date` datetime DEFAULT NULL,
++`sspo_remote_title` varchar(255) NOT NULL,
++`sspo_remote_url` varchar(255) NOT NULL,
++`sspo_remote_desc` text NOT NULL,
++`sspo_remote_image` varchar(255) NOT NULL,
++`sspo_obj_status` varchar(1) NOT NULL DEFAULT 'A',
++`sspo_cr_date` datetime NOT NULL DEFAULT '1970-01-01 00:00:00',
++`sspo_cr_uid` int(11) NOT NULL DEFAULT '0',
++`sspo_lu_date` datetime NOT NULL DEFAULT '1970-01-01 00:00:00',
++`sspo_lu_uid` int(11) NOT NULL DEFAULT '0',
++PRIMARY KEY (`sspo_id`),
++KEY `post_uid` (`sspo_uid`,`sspo_cr_date`)
++) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;
++Warnings:
++Warning	1286	Unknown storage engine 'InnoDB'
++Warning	1266	Using storage engine MyISAM for table 't1'
++INSERT INTO t1 VALUES (1,2,'P','test1','',0,'','',NULL,'','','','','A','2013-09-30 00:19:32',2,'2013-09-30 00:19:32',2),(2,2,'P','bbb','',0,'','',NULL,'','','','','A','2013-10-02 15:06:35',2,'2013-10-02 15:06:35',2);
++CREATE TABLE `t2` (
++`spoo_id` int(11) NOT NULL AUTO_INCREMENT,
++`spoo_user_type_id` int(11) NOT NULL DEFAULT '0',
++`spoo_uid` int(11) NOT NULL DEFAULT '0',
++`spoo_option_id` int(11) NOT NULL DEFAULT '0',
++`spoo_value` varchar(10000) NOT NULL,
++`spoo_obj_status` varchar(1) NOT NULL DEFAULT 'A',
++`spoo_cr_date` datetime NOT NULL DEFAULT '1970-01-01 00:00:00',
++`spoo_cr_uid` int(11) NOT NULL DEFAULT '0',
++`spoo_lu_date` datetime NOT NULL DEFAULT '1970-01-01 00:00:00',
++`spoo_lu_uid` int(11) NOT NULL DEFAULT '0',
++PRIMARY KEY (`spoo_id`),
++KEY `object_option_main_idx` (`spoo_user_type_id`,`spoo_uid`,`spoo_option_id`,`spoo_value`(255))
++) ENGINE=InnoDB AUTO_INCREMENT=107 DEFAULT CHARSET=utf8;
++Warnings:
++Warning	1286	Unknown storage engine 'InnoDB'
++Warning	1266	Using storage engine MyISAM for table 't2'
++INSERT INTO `t2` VALUES (19,1,2,6,'Dortmund','A','2013-09-26 01:36:51',2,'2013-09-26 01:36:51',2),(20,1,2,8,'49','A','2013-09-26 01:36:51',2,'2013-09-26 01:36:51',2);
++SELECT Count(*)
++FROM   t1 AS tbl
++LEFT JOIN t2 a
++ON a.spoo_uid = sspo_uid
++AND a.spoo_option_id = 1
++LEFT JOIN t2 b
++ON b.spoo_uid = sspo_uid
++AND b.spoo_option_id = 2
++LEFT JOIN t2 c
++ON c.spoo_uid = sspo_uid
++AND c.spoo_option_id = 3
++LEFT JOIN t2 d
++ON d.spoo_uid = sspo_uid
++AND d.spoo_option_id = 5
++LEFT JOIN t2 e
++ON e.spoo_uid = sspo_uid
++AND e.spoo_option_id = 4
++LEFT JOIN t2 f
++ON f.spoo_uid = sspo_uid
++AND f.spoo_option_id = 11
++LEFT JOIN t2 g
++ON g.spoo_uid = sspo_uid
++AND g.spoo_option_id = 7
++LEFT JOIN t2 h
++ON h.spoo_uid = sspo_uid
++AND h.spoo_option_id = 10
++LEFT JOIN t2 i
++ON i.spoo_uid = sspo_uid
++AND i.spoo_option_id = 18
++LEFT JOIN t2 j
++ON j.spoo_uid = sspo_uid
++AND j.spoo_option_id = 6
++GROUP  BY a.spoo_value,
++b.spoo_value,
++c.spoo_value,
++d.spoo_value,
++e.spoo_value,
++f.spoo_value,
++g.spoo_value,
++h.spoo_value,
++i.spoo_value,
++j.spoo_value;
++Count(*)
++2
++drop table t1,t2;
+diff -up mariadb-5.5.36/mysql-test/t/stack-crash.test.rhbz1065676 mariadb-5.5.36/mysql-test/t/stack-crash.test
+--- mariadb-5.5.36/mysql-test/t/stack-crash.test.rhbz1065676	2014-03-11 18:20:56.344327004 +0100
++++ mariadb-5.5.36/mysql-test/t/stack-crash.test	2014-03-11 18:20:56.344327004 +0100
+@@ -0,0 +1,96 @@
++#
++# Test to ensure that we don't get stack overflows
++#
++
++drop table if exists t1,t2;
++
++#
++# MDEV-5724
++# Server crashes on SQL select containing more group by and left join
++# statements
++# This was because record_buffer was 300,000 bytes and caused stack overflow
++#
++
++CREATE TABLE t1 (
++  `sspo_id` int(11) NOT NULL AUTO_INCREMENT,
++  `sspo_uid` int(11) NOT NULL DEFAULT '0',
++  `sspo_type` varchar(1) NOT NULL DEFAULT 'P',
++  `sspo_text` longtext NOT NULL,
++  `sspo_image` varchar(255) NOT NULL,
++  `sspo_source` int(11) NOT NULL DEFAULT '0',
++  `sspo_event_name` varchar(255) NOT NULL DEFAULT '',
++  `sspo_event_location` varchar(255) NOT NULL DEFAULT '',
++  `sspo_event_date` datetime DEFAULT NULL,
++  `sspo_remote_title` varchar(255) NOT NULL,
++  `sspo_remote_url` varchar(255) NOT NULL,
++  `sspo_remote_desc` text NOT NULL,
++  `sspo_remote_image` varchar(255) NOT NULL,
++  `sspo_obj_status` varchar(1) NOT NULL DEFAULT 'A',
++  `sspo_cr_date` datetime NOT NULL DEFAULT '1970-01-01 00:00:00',
++  `sspo_cr_uid` int(11) NOT NULL DEFAULT '0',
++  `sspo_lu_date` datetime NOT NULL DEFAULT '1970-01-01 00:00:00',
++  `sspo_lu_uid` int(11) NOT NULL DEFAULT '0',
++  PRIMARY KEY (`sspo_id`),
++  KEY `post_uid` (`sspo_uid`,`sspo_cr_date`)
++) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;
++INSERT INTO t1 VALUES (1,2,'P','test1','',0,'','',NULL,'','','','','A','2013-09-30 00:19:32',2,'2013-09-30 00:19:32',2),(2,2,'P','bbb','',0,'','',NULL,'','','','','A','2013-10-02 15:06:35',2,'2013-10-02 15:06:35',2);
++
++CREATE TABLE `t2` (
++  `spoo_id` int(11) NOT NULL AUTO_INCREMENT,
++  `spoo_user_type_id` int(11) NOT NULL DEFAULT '0',
++  `spoo_uid` int(11) NOT NULL DEFAULT '0',
++  `spoo_option_id` int(11) NOT NULL DEFAULT '0',
++  `spoo_value` varchar(10000) NOT NULL,
++  `spoo_obj_status` varchar(1) NOT NULL DEFAULT 'A',
++  `spoo_cr_date` datetime NOT NULL DEFAULT '1970-01-01 00:00:00',
++  `spoo_cr_uid` int(11) NOT NULL DEFAULT '0',
++  `spoo_lu_date` datetime NOT NULL DEFAULT '1970-01-01 00:00:00',
++  `spoo_lu_uid` int(11) NOT NULL DEFAULT '0',
++  PRIMARY KEY (`spoo_id`),
++  KEY `object_option_main_idx` (`spoo_user_type_id`,`spoo_uid`,`spoo_option_id`,`spoo_value`(255))
++) ENGINE=InnoDB AUTO_INCREMENT=107 DEFAULT CHARSET=utf8;
++INSERT INTO `t2` VALUES (19,1,2,6,'Dortmund','A','2013-09-26 01:36:51',2,'2013-09-26 01:36:51',2),(20,1,2,8,'49','A','2013-09-26 01:36:51',2,'2013-09-26 01:36:51',2);
++
++SELECT Count(*)
++FROM   t1 AS tbl
++       LEFT JOIN t2 a
++              ON a.spoo_uid = sspo_uid
++                 AND a.spoo_option_id = 1
++       LEFT JOIN t2 b
++              ON b.spoo_uid = sspo_uid
++                 AND b.spoo_option_id = 2
++       LEFT JOIN t2 c
++              ON c.spoo_uid = sspo_uid
++                 AND c.spoo_option_id = 3
++       LEFT JOIN t2 d
++              ON d.spoo_uid = sspo_uid
++                 AND d.spoo_option_id = 5
++       LEFT JOIN t2 e
++              ON e.spoo_uid = sspo_uid
++                 AND e.spoo_option_id = 4
++       LEFT JOIN t2 f
++              ON f.spoo_uid = sspo_uid
++                 AND f.spoo_option_id = 11
++       LEFT JOIN t2 g
++              ON g.spoo_uid = sspo_uid
++                 AND g.spoo_option_id = 7
++       LEFT JOIN t2 h
++              ON h.spoo_uid = sspo_uid
++                 AND h.spoo_option_id = 10
++       LEFT JOIN t2 i
++              ON i.spoo_uid = sspo_uid
++                 AND i.spoo_option_id = 18
++       LEFT JOIN t2 j
++              ON j.spoo_uid = sspo_uid
++                 AND j.spoo_option_id = 6
++GROUP  BY a.spoo_value,
++          b.spoo_value,
++          c.spoo_value,
++          d.spoo_value,
++          e.spoo_value,
++          f.spoo_value,
++          g.spoo_value,
++          h.spoo_value,
++          i.spoo_value,
++          j.spoo_value;
++drop table t1,t2;
+diff -up mariadb-5.5.36/storage/maria/ma_blockrec.c.rhbz1065676 mariadb-5.5.36/storage/maria/ma_blockrec.c
+--- mariadb-5.5.36/storage/maria/ma_blockrec.c.rhbz1065676	2014-02-24 00:50:19.000000000 +0100
++++ mariadb-5.5.36/storage/maria/ma_blockrec.c	2014-03-11 18:20:56.347327004 +0100
+@@ -5144,7 +5144,12 @@ my_bool _ma_cmp_block_unique(MARIA_HA *i
+   int error;
+   DBUG_ENTER("_ma_cmp_block_unique");
+ 
+-  if (!(old_record= my_alloca(info->s->base.reclength)))
++  /*
++    Don't allocate more than 16K on the stack to ensure we don't get
++    stack overflow.
++  */
++  if (!(old_record= my_safe_alloca(info->s->base.reclength,
++                                   MARIA_MAX_RECORD_ON_STACK)))
+     DBUG_RETURN(1);
+ 
+   /* Don't let the compare destroy blobs that may be in use */
+@@ -5166,7 +5171,8 @@ my_bool _ma_cmp_block_unique(MARIA_HA *i
+     info->rec_buff_size= org_rec_buff_size;
+   }
+   DBUG_PRINT("exit", ("result: %d", error));
+-  my_afree(old_record);
++  my_safe_afree(old_record, info->s->base.reclength,
++                MARIA_MAX_RECORD_ON_STACK);
+   DBUG_RETURN(error != 0);
+ }
+ 
+diff -up mariadb-5.5.36/storage/maria/ma_dynrec.c.rhbz1065676 mariadb-5.5.36/storage/maria/ma_dynrec.c
+--- mariadb-5.5.36/storage/maria/ma_dynrec.c.rhbz1065676	2014-02-24 00:50:16.000000000 +0100
++++ mariadb-5.5.36/storage/maria/ma_dynrec.c	2014-03-11 18:20:56.348327004 +0100
+@@ -36,12 +36,6 @@ static my_bool delete_dynamic_record(MAR
+ static my_bool _ma_cmp_buffer(File file, const uchar *buff, my_off_t filepos,
+                               uint length);
+ 
+-/* Play it safe; We have a small stack when using threads */
+-#undef my_alloca
+-#undef my_afree
+-#define my_alloca(A) my_malloc((A),MYF(0))
+-#define my_afree(A) my_free((A))
+-
+ 	/* Interface function from MARIA_HA */
+ 
+ #ifdef HAVE_MMAP
+@@ -256,7 +250,8 @@ my_bool _ma_write_blob_record(MARIA_HA *
+ 	  MARIA_DYN_DELETE_BLOCK_HEADER+1);
+   reclength= (info->s->base.pack_reclength +
+ 	      _ma_calc_total_blob_length(info,record)+ extra);
+-  if (!(rec_buff=(uchar*) my_alloca(reclength)))
++  if (!(rec_buff=(uchar*) my_safe_alloca(reclength,
++                                         MARIA_MAX_RECORD_ON_STACK)))
+   {
+     my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
+     return(1);
+@@ -270,7 +265,7 @@ my_bool _ma_write_blob_record(MARIA_HA *
+   error= write_dynamic_record(info,
+                               rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
+                               reclength2);
+-  my_afree(rec_buff);
++  my_safe_afree(rec_buff, reclength, MARIA_MAX_RECORD_ON_STACK);
+   return(error != 0);
+ }
+ 
+@@ -294,7 +289,8 @@ my_bool _ma_update_blob_record(MARIA_HA
+     return 1;
+   }
+ #endif
+-  if (!(rec_buff=(uchar*) my_alloca(reclength)))
++  if (!(rec_buff=(uchar*) my_safe_alloca(reclength,
++                                         MARIA_MAX_RECORD_ON_STACK)))
+   {
+     my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
+     return(1);
+@@ -304,7 +300,7 @@ my_bool _ma_update_blob_record(MARIA_HA
+   error=update_dynamic_record(info,pos,
+ 			      rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
+ 			      reclength);
+-  my_afree(rec_buff);
++  my_safe_afree(rec_buff, reclength, MARIA_MAX_RECORD_ON_STACK);
+   return(error != 0);
+ }
+ 
+@@ -1559,7 +1555,8 @@ my_bool _ma_cmp_dynamic_unique(MARIA_HA
+   my_bool error;
+   DBUG_ENTER("_ma_cmp_dynamic_unique");
+ 
+-  if (!(old_record=my_alloca(info->s->base.reclength)))
++  if (!(old_record= my_safe_alloca(info->s->base.reclength,
++                                   MARIA_MAX_RECORD_ON_STACK)))
+     DBUG_RETURN(1);
+ 
+   /* Don't let the compare destroy blobs that may be in use */
+@@ -1580,7 +1577,8 @@ my_bool _ma_cmp_dynamic_unique(MARIA_HA
+     info->rec_buff=      old_rec_buff;
+     info->rec_buff_size= old_rec_buff_size;
+   }
+-  my_afree(old_record);
++  my_safe_afree(old_record, info->s->base.reclength,
++                MARIA_MAX_RECORD_ON_STACK);
+   DBUG_RETURN(error);
+ }
+ 
+@@ -1595,6 +1593,9 @@ my_bool _ma_cmp_dynamic_record(register
+   uchar *buffer;
+   MARIA_BLOCK_INFO block_info;
+   my_bool error= 1;
++  size_t buffer_length;
++  LINT_INIT(buffer_length);
++
+   DBUG_ENTER("_ma_cmp_dynamic_record");
+ 
+   if (info->opt_flag & WRITE_CACHE_USED)
+@@ -1612,8 +1613,10 @@ my_bool _ma_cmp_dynamic_record(register
+   {						/* If check isn't disabled  */
+     if (info->s->base.blobs)
+     {
+-      if (!(buffer=(uchar*) my_alloca(info->s->base.pack_reclength+
+-				     _ma_calc_total_blob_length(info,record))))
++      buffer_length= (info->s->base.pack_reclength +
++                      _ma_calc_total_blob_length(info,record));
++      if (!(buffer=(uchar*) my_safe_alloca(buffer_length,
++                                           MARIA_MAX_RECORD_ON_STACK)))
+ 	DBUG_RETURN(1);
+     }
+     reclength= _ma_rec_pack(info,buffer,record);
+@@ -1665,7 +1668,7 @@ my_bool _ma_cmp_dynamic_record(register
+   error= 0;
+ err:
+   if (buffer != info->rec_buff)
+-    my_afree(buffer);
++    my_safe_afree(buffer, buffer_length, MARIA_MAX_RECORD_ON_STACK);
+   DBUG_PRINT("exit", ("result: %d", error));
+   DBUG_RETURN(error);
+ }
+diff -up mariadb-5.5.36/storage/maria/maria_def.h.rhbz1065676 mariadb-5.5.36/storage/maria/maria_def.h
+--- mariadb-5.5.36/storage/maria/maria_def.h.rhbz1065676	2014-02-24 00:50:21.000000000 +0100
++++ mariadb-5.5.36/storage/maria/maria_def.h	2014-03-11 18:20:56.348327004 +0100
+@@ -42,6 +42,7 @@
+ 
+ #define MAX_NONMAPPED_INSERTS 1000
+ #define MARIA_MAX_TREE_LEVELS 32
++#define MARIA_MAX_RECORD_ON_STACK 16384
+ 
+ /* maria_open() flag, specific for maria_pack */
+ #define HA_OPEN_IGNORE_MOVED_STATE (1U << 30)
+diff -up mariadb-5.5.36/storage/maria/maria_pack.c.rhbz1065676 mariadb-5.5.36/storage/maria/maria_pack.c
+--- mariadb-5.5.36/storage/maria/maria_pack.c.rhbz1065676	2014-02-24 00:50:16.000000000 +0100
++++ mariadb-5.5.36/storage/maria/maria_pack.c	2014-03-11 18:20:56.351327005 +0100
+@@ -861,7 +861,7 @@ static int get_statistic(PACK_MRG_INFO *
+ 
+   reclength=  mrg->file[0]->s->base.reclength;
+   null_bytes= mrg->file[0]->s->base.null_bytes;
+-  record=(uchar*) my_alloca(reclength);
++  record=(uchar*) my_safe_alloca(reclength, MARIA_MAX_RECORD_ON_STACK);
+   end_count=huff_counts+mrg->file[0]->s->base.fields;
+   record_count=0; glob_crc=0;
+   max_blob_length=0;
+@@ -1145,7 +1145,7 @@ static int get_statistic(PACK_MRG_INFO *
+ 
+   mrg->records=record_count;
+   mrg->max_blob_length=max_blob_length;
+-  my_afree(record);
++  my_safe_afree(record, reclength, MARIA_MAX_RECORD_ON_STACK);
+   DBUG_RETURN(error != HA_ERR_END_OF_FILE);
+ }
+ 
+@@ -2415,7 +2415,8 @@ static int compress_maria_file(PACK_MRG_
+   DBUG_ENTER("compress_maria_file");
+ 
+   /* Allocate a buffer for the records (excluding blobs). */
+-  if (!(record=(uchar*) my_alloca(isam_file->s->base.reclength)))
++  if (!(record=(uchar*) my_safe_alloca(isam_file->s->base.reclength,
++                                       MARIA_MAX_RECORD_ON_STACK)))
+     return -1;
+ 
+   end_count=huff_counts+isam_file->s->base.fields;
+@@ -2778,7 +2779,8 @@ static int compress_maria_file(PACK_MRG_
+   if (verbose >= 2)
+     printf("wrote %s records.\n", llstr((longlong) record_count, llbuf));
+ 
+-  my_afree(record);
++  my_safe_afree(record, isam_file->s->base.reclength,
++                MARIA_MAX_RECORD_ON_STACK);
+   mrg->ref_length=max_pack_length;
+   mrg->min_pack_length=max_record_length ? min_record_length : 0;
+   mrg->max_pack_length=max_record_length;
diff --git a/mariadb.spec b/mariadb.spec
index 19c714a..d91bc97 100644
--- a/mariadb.spec
+++ b/mariadb.spec
@@ -7,7 +7,7 @@
 
 Name: mariadb
 Version: 5.5.36
-Release: 1%{?dist}
+Release: 2%{?dist}
 Epoch: 1
 
 Summary: A community developed branch of MySQL
@@ -69,6 +69,7 @@ Patch17: mariadb-covscan-signexpr.patch
 Patch18: mariadb-covscan-stroverflow.patch
 Patch19: mariadb-config.patch
 Patch20: mariadb-ssltest.patch
+Patch21: mariadb-rhbz1065676.patch
 
 BuildRequires: perl, readline-devel, openssl-devel
 BuildRequires: cmake, ncurses-devel, zlib-devel, libaio-devel
@@ -269,6 +270,7 @@ MariaDB is a community developed branch of MySQL.
 %patch18 -p1
 %patch19 -p1
 %patch20 -p1
+%patch21 -p1
 
 # workaround for upstream bug #56342
 rm -f mysql-test/t/ssl_8k_key-master.opt
@@ -804,6 +806,10 @@ fi
 %{_mandir}/man1/mysql_client_test.1*
 
 %changelog
+* Wed Mar 12 2014 Honza Horak <hhorak at redhat.com> - 1:5.5.36-2
+- Server crashes on SQL select containing more group by and left join statements using innodb tables
+  Resolves: #1065676
+
 * Thu Mar 06 2014 Honza Horak <hhorak at redhat.com> - 1:5.5.36-1
 - Rebase to 5.5.36
   https://kb.askmonty.org/en/mariadb-5536-changelog/


More information about the scm-commits mailing list