diff options
author | Michael Widenius <monty@mariadb.org> | 2014-03-10 21:14:38 +0200 |
---|---|---|
committer | Michael Widenius <monty@mariadb.org> | 2014-03-10 21:14:38 +0200 |
commit | 3b55c2fe218ed8bb740da25e8f228e9a8ca72794 (patch) | |
tree | 13ee18cc59f2c1c43bbf5eee491c96cfc00af40d /storage/maria | |
parent | b07f9f72dc131acad58fb20a188c5014312f6849 (diff) | |
download | mariadb-git-3b55c2fe218ed8bb740da25e8f228e9a8ca72794.tar.gz |
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()
Diffstat (limited to 'storage/maria')
-rw-r--r-- | storage/maria/ma_blockrec.c | 10 | ||||
-rw-r--r-- | storage/maria/ma_dynrec.c | 33 | ||||
-rw-r--r-- | storage/maria/maria_def.h | 1 | ||||
-rw-r--r-- | storage/maria/maria_pack.c | 10 |
4 files changed, 33 insertions, 21 deletions
diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index c6371287063..7e996d0ced8 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -5144,7 +5144,12 @@ my_bool _ma_cmp_block_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def, 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 *info, MARIA_UNIQUEDEF *def, 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 --git a/storage/maria/ma_dynrec.c b/storage/maria/ma_dynrec.c index b0280f5278b..a18ea157954 100644 --- a/storage/maria/ma_dynrec.c +++ b/storage/maria/ma_dynrec.c @@ -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, 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 *info, const uchar *record) 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 *info, const uchar *record) 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 *info, MARIA_RECORD_POS pos, 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 *info, MARIA_RECORD_POS pos, 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 *info, MARIA_UNIQUEDEF *def, 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, MARIA_UNIQUEDEF *def, 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 MARIA_HA *info, 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 MARIA_HA *info, { /* 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 MARIA_HA *info, 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 --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h index 9b57dd2847d..ab4ade30c44 100644 --- a/storage/maria/maria_def.h +++ b/storage/maria/maria_def.h @@ -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 --git a/storage/maria/maria_pack.c b/storage/maria/maria_pack.c index 66085a8981b..26d57ade59a 100644 --- a/storage/maria/maria_pack.c +++ b/storage/maria/maria_pack.c @@ -861,7 +861,7 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts) 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,HUFF_COUNTS *huff_counts) 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_INFO *mrg, HUFF_COUNTS *huff_counts) 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_INFO *mrg, HUFF_COUNTS *huff_counts) 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; |