mariadb/mysys/mulalloc.c
Monty afa9cb7519 Fixed overrun in key cache if one tried to allocate a key cache
of more than 45G with a key_cache_block_size of 1024 or less.

The problem was that some of the arguments to my_multi_malloc() got to be
more than 4G.

Fix:
- Inntroduced my_multi_malloc_large() that can handle big regions.
- Changed MyISAM and Aria key caches to use my_multi_malloc_large().

I didn't change the default my_multi_malloc() as this would be a too big
patch and we don't allocate 4G blocks anywhere else.
2015-08-13 01:27:23 +03:00

108 lines
2.6 KiB
C

/* Copyright (c) 2000, 2002, 2003, 2007 MySQL AB
Use is subject to license terms
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
#include "mysys_priv.h"
#include <stdarg.h>
/*
Malloc many pointers at the same time
Only ptr1 can be free'd, and doing this will free all
the memory allocated. ptr2, etc all point inside big allocated
memory area.
SYNOPSIS
my_multi_malloc()
myFlags Flags
ptr1, length1 Multiple arguments terminated by null ptr
ptr2, length2 ...
...
NULL
*/
void* my_multi_malloc(myf myFlags, ...)
{
va_list args;
char **ptr,*start,*res;
size_t tot_length,length;
DBUG_ENTER("my_multi_malloc");
va_start(args,myFlags);
tot_length=0;
while ((ptr=va_arg(args, char **)))
{
length=va_arg(args,uint);
tot_length+=ALIGN_SIZE(length);
}
va_end(args);
if (!(start=(char *) my_malloc(tot_length,myFlags)))
DBUG_RETURN(0); /* purecov: inspected */
va_start(args,myFlags);
res=start;
while ((ptr=va_arg(args, char **)))
{
*ptr=res;
length=va_arg(args,uint);
res+=ALIGN_SIZE(length);
}
va_end(args);
DBUG_RETURN((void*) start);
}
/*
Same as my_multi_malloc, but each entry can be over 4G
SYNOPSIS
my_multi_malloc()
myFlags Flags
ptr1, length1 Multiple arguments terminated by null ptr
ptr2, length2 ...
...
NULL
*/
void *my_multi_malloc_large(myf myFlags, ...)
{
va_list args;
char **ptr,*start,*res;
size_t tot_length,length;
DBUG_ENTER("my_multi_malloc");
va_start(args,myFlags);
tot_length=0;
while ((ptr=va_arg(args, char **)))
{
length=va_arg(args,ulonglong);
tot_length+=ALIGN_SIZE(length);
}
va_end(args);
if (!(start=(char *) my_malloc(tot_length, myFlags)))
DBUG_RETURN(0); /* purecov: inspected */
va_start(args,myFlags);
res=start;
while ((ptr=va_arg(args, char **)))
{
*ptr=res;
length=va_arg(args,ulonglong);
res+=ALIGN_SIZE(length);
}
va_end(args);
DBUG_RETURN((void*) start);
}