Commit 3b55c2fe authored by Michael Widenius's avatar Michael Widenius

Fixed MDEV-5724 "Server crashes on SQL select containing more group by and...

Fixed MDEV-5724 "Server crashes on SQL select containing more group by and left join statements using innodb tables"

The problem was that a big record was allocated on the stack, which casued stack to run out.

Fixed by using my_safe_alloca() instead of my_alloca() when allocating records.
Now only records <= 16384 are allocated on the stack.

mysql-test/r/stack-crash.result:
  Added test case
mysql-test/t/stack-crash.test:
  Added test case
storage/maria/ma_blockrec.c:
  Use my_safe_alloca() instead of my_alloca()
storage/maria/ma_dynrec.c:
  Use my_safe_alloca() instead of my_alloca()
storage/maria/maria_def.h:
  Added MARIA_MAX_RECORD_ON_STACK
storage/maria/maria_pack.c:
  Use my_safe_alloca() instead of my_alloca()
parent b07f9f72
drop table if exists t1,t2;
Warnings:
Note 1051 Unknown table 'test.t1'
Note 1051 Unknown table 'test.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;
#
# 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;
...@@ -5144,7 +5144,12 @@ my_bool _ma_cmp_block_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def, ...@@ -5144,7 +5144,12 @@ my_bool _ma_cmp_block_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
int error; int error;
DBUG_ENTER("_ma_cmp_block_unique"); 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); DBUG_RETURN(1);
/* Don't let the compare destroy blobs that may be in use */ /* Don't let the compare destroy blobs that may be in use */
...@@ -5166,7 +5171,8 @@ my_bool _ma_cmp_block_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def, ...@@ -5166,7 +5171,8 @@ my_bool _ma_cmp_block_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
info->rec_buff_size= org_rec_buff_size; info->rec_buff_size= org_rec_buff_size;
} }
DBUG_PRINT("exit", ("result: %d", error)); 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); DBUG_RETURN(error != 0);
} }
......
...@@ -36,12 +36,6 @@ static my_bool delete_dynamic_record(MARIA_HA *info,MARIA_RECORD_POS filepos, ...@@ -36,12 +36,6 @@ static my_bool delete_dynamic_record(MARIA_HA *info,MARIA_RECORD_POS filepos,
static my_bool _ma_cmp_buffer(File file, const uchar *buff, my_off_t filepos, static my_bool _ma_cmp_buffer(File file, const uchar *buff, my_off_t filepos,
uint length); 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 */ /* Interface function from MARIA_HA */
#ifdef HAVE_MMAP #ifdef HAVE_MMAP
...@@ -256,7 +250,8 @@ my_bool _ma_write_blob_record(MARIA_HA *info, const uchar *record) ...@@ -256,7 +250,8 @@ my_bool _ma_write_blob_record(MARIA_HA *info, const uchar *record)
MARIA_DYN_DELETE_BLOCK_HEADER+1); MARIA_DYN_DELETE_BLOCK_HEADER+1);
reclength= (info->s->base.pack_reclength + reclength= (info->s->base.pack_reclength +
_ma_calc_total_blob_length(info,record)+ extra); _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 */ my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
return(1); return(1);
...@@ -270,7 +265,7 @@ my_bool _ma_write_blob_record(MARIA_HA *info, const uchar *record) ...@@ -270,7 +265,7 @@ my_bool _ma_write_blob_record(MARIA_HA *info, const uchar *record)
error= write_dynamic_record(info, error= write_dynamic_record(info,
rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER), rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
reclength2); reclength2);
my_afree(rec_buff); my_safe_afree(rec_buff, reclength, MARIA_MAX_RECORD_ON_STACK);
return(error != 0); return(error != 0);
} }
...@@ -294,7 +289,8 @@ my_bool _ma_update_blob_record(MARIA_HA *info, MARIA_RECORD_POS pos, ...@@ -294,7 +289,8 @@ my_bool _ma_update_blob_record(MARIA_HA *info, MARIA_RECORD_POS pos,
return 1; return 1;
} }
#endif #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 */ my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
return(1); return(1);
...@@ -304,7 +300,7 @@ my_bool _ma_update_blob_record(MARIA_HA *info, MARIA_RECORD_POS pos, ...@@ -304,7 +300,7 @@ my_bool _ma_update_blob_record(MARIA_HA *info, MARIA_RECORD_POS pos,
error=update_dynamic_record(info,pos, error=update_dynamic_record(info,pos,
rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER), rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
reclength); reclength);
my_afree(rec_buff); my_safe_afree(rec_buff, reclength, MARIA_MAX_RECORD_ON_STACK);
return(error != 0); return(error != 0);
} }
...@@ -1559,7 +1555,8 @@ my_bool _ma_cmp_dynamic_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def, ...@@ -1559,7 +1555,8 @@ my_bool _ma_cmp_dynamic_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
my_bool error; my_bool error;
DBUG_ENTER("_ma_cmp_dynamic_unique"); 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); DBUG_RETURN(1);
/* Don't let the compare destroy blobs that may be in use */ /* 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, MARIA_UNIQUEDEF *def, ...@@ -1580,7 +1577,8 @@ my_bool _ma_cmp_dynamic_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
info->rec_buff= old_rec_buff; info->rec_buff= old_rec_buff;
info->rec_buff_size= old_rec_buff_size; 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); DBUG_RETURN(error);
} }
...@@ -1595,6 +1593,9 @@ my_bool _ma_cmp_dynamic_record(register MARIA_HA *info, ...@@ -1595,6 +1593,9 @@ my_bool _ma_cmp_dynamic_record(register MARIA_HA *info,
uchar *buffer; uchar *buffer;
MARIA_BLOCK_INFO block_info; MARIA_BLOCK_INFO block_info;
my_bool error= 1; my_bool error= 1;
size_t buffer_length;
LINT_INIT(buffer_length);
DBUG_ENTER("_ma_cmp_dynamic_record"); DBUG_ENTER("_ma_cmp_dynamic_record");
if (info->opt_flag & WRITE_CACHE_USED) if (info->opt_flag & WRITE_CACHE_USED)
...@@ -1612,8 +1613,10 @@ my_bool _ma_cmp_dynamic_record(register MARIA_HA *info, ...@@ -1612,8 +1613,10 @@ my_bool _ma_cmp_dynamic_record(register MARIA_HA *info,
{ /* If check isn't disabled */ { /* If check isn't disabled */
if (info->s->base.blobs) if (info->s->base.blobs)
{ {
if (!(buffer=(uchar*) my_alloca(info->s->base.pack_reclength+ buffer_length= (info->s->base.pack_reclength +
_ma_calc_total_blob_length(info,record)))) _ma_calc_total_blob_length(info,record));
if (!(buffer=(uchar*) my_safe_alloca(buffer_length,
MARIA_MAX_RECORD_ON_STACK)))
DBUG_RETURN(1); DBUG_RETURN(1);
} }
reclength= _ma_rec_pack(info,buffer,record); reclength= _ma_rec_pack(info,buffer,record);
...@@ -1665,7 +1668,7 @@ my_bool _ma_cmp_dynamic_record(register MARIA_HA *info, ...@@ -1665,7 +1668,7 @@ my_bool _ma_cmp_dynamic_record(register MARIA_HA *info,
error= 0; error= 0;
err: err:
if (buffer != info->rec_buff) 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_PRINT("exit", ("result: %d", error));
DBUG_RETURN(error); DBUG_RETURN(error);
} }
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#define MAX_NONMAPPED_INSERTS 1000 #define MAX_NONMAPPED_INSERTS 1000
#define MARIA_MAX_TREE_LEVELS 32 #define MARIA_MAX_TREE_LEVELS 32
#define MARIA_MAX_RECORD_ON_STACK 16384
/* maria_open() flag, specific for maria_pack */ /* maria_open() flag, specific for maria_pack */
#define HA_OPEN_IGNORE_MOVED_STATE (1U << 30) #define HA_OPEN_IGNORE_MOVED_STATE (1U << 30)
......
...@@ -861,7 +861,7 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts) ...@@ -861,7 +861,7 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
reclength= mrg->file[0]->s->base.reclength; reclength= mrg->file[0]->s->base.reclength;
null_bytes= mrg->file[0]->s->base.null_bytes; 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; end_count=huff_counts+mrg->file[0]->s->base.fields;
record_count=0; glob_crc=0; record_count=0; glob_crc=0;
max_blob_length=0; max_blob_length=0;
...@@ -1145,7 +1145,7 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts) ...@@ -1145,7 +1145,7 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
mrg->records=record_count; mrg->records=record_count;
mrg->max_blob_length=max_blob_length; 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); DBUG_RETURN(error != HA_ERR_END_OF_FILE);
} }
...@@ -2415,7 +2415,8 @@ static int compress_maria_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) ...@@ -2415,7 +2415,8 @@ static int compress_maria_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
DBUG_ENTER("compress_maria_file"); DBUG_ENTER("compress_maria_file");
/* Allocate a buffer for the records (excluding blobs). */ /* 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; return -1;
end_count=huff_counts+isam_file->s->base.fields; end_count=huff_counts+isam_file->s->base.fields;
...@@ -2778,7 +2779,8 @@ static int compress_maria_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) ...@@ -2778,7 +2779,8 @@ static int compress_maria_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
if (verbose >= 2) if (verbose >= 2)
printf("wrote %s records.\n", llstr((longlong) record_count, llbuf)); 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->ref_length=max_pack_length;
mrg->min_pack_length=max_record_length ? min_record_length : 0; mrg->min_pack_length=max_record_length ? min_record_length : 0;
mrg->max_pack_length=max_record_length; mrg->max_pack_length=max_record_length;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment