mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
35945019ea
Too many cursors (more than 1024) could lead to memory corruption. This affects both, stored routines and C API cursors, and the threshold is per-server, not per-connection. Similarly, the corruption could happen when the server was under heavy load (executing more than 1024 simultaneous complex queries), and this is the reason why this bug is fixed in 4.1, which doesn't support cursors. The corruption was caused by a bug in the temporary tables code, when an attempt to create a table could lead to a write beyond allocated space. Note, that only internal tables were affected (the tables created internally by the server to resolve the query), not tables created with CREATE TEMPORARY TABLE. Another pre-condition for the bug is TRUE value of --temp-pool startup option, which, however, is a default. The cause of a bug was that random memory was overwritten in bitmap_set_next() due to out-of-bound memory access. mysys/my_bitmap.c: Local 'bitmap_size' is measured in bytes, no need to multiply it by 8. sql/sql_select.cc: Clear the temp_pool_slot bit only if we have set it previously.
329 lines
7.3 KiB
C
329 lines
7.3 KiB
C
/* Copyright (C) 2000 MySQL AB
|
|
|
|
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; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
/*
|
|
Handling of uchar arrays as large bitmaps.
|
|
|
|
API limitations (or, rather asserted safety assumptions,
|
|
to encourage correct programming)
|
|
|
|
* the size of the used bitmap is less than ~(uint) 0
|
|
* it's a multiple of 8 (for efficiency reasons)
|
|
* when arguments are a bitmap and a bit number, the number
|
|
must be within bitmap size
|
|
* bitmap_set_prefix() is an exception - one can use ~0 to set all bits
|
|
* when both arguments are bitmaps, they must be of the same size
|
|
* bitmap_intersect() is an exception :)
|
|
(for for Bitmap::intersect(ulonglong map2buff))
|
|
|
|
TODO:
|
|
Make assembler THREAD safe versions of these using test-and-set instructions
|
|
*/
|
|
|
|
#include "mysys_priv.h"
|
|
#include <my_bitmap.h>
|
|
#include <m_string.h>
|
|
|
|
static inline void bitmap_lock(MY_BITMAP* map)
|
|
{
|
|
#ifdef THREAD
|
|
if (map->mutex)
|
|
pthread_mutex_lock(map->mutex);
|
|
#endif
|
|
}
|
|
|
|
static inline void bitmap_unlock(MY_BITMAP* map)
|
|
{
|
|
#ifdef THREAD
|
|
if (map->mutex)
|
|
pthread_mutex_unlock(map->mutex);
|
|
#endif
|
|
}
|
|
|
|
|
|
my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size,
|
|
my_bool thread_safe)
|
|
{
|
|
DBUG_ENTER("bitmap_init");
|
|
|
|
DBUG_ASSERT((bitmap_size & 7) == 0);
|
|
bitmap_size/=8;
|
|
if (!(map->bitmap=buf) &&
|
|
!(map->bitmap= (uchar*) my_malloc(bitmap_size +
|
|
(thread_safe ?
|
|
sizeof(pthread_mutex_t) : 0),
|
|
MYF(MY_WME | MY_ZEROFILL))))
|
|
return 1;
|
|
map->bitmap_size=bitmap_size;
|
|
#ifdef THREAD
|
|
if (thread_safe)
|
|
{
|
|
map->mutex=(pthread_mutex_t *)(map->bitmap+bitmap_size);
|
|
pthread_mutex_init(map->mutex, MY_MUTEX_INIT_FAST);
|
|
}
|
|
else
|
|
map->mutex=0;
|
|
#endif
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
void bitmap_free(MY_BITMAP *map)
|
|
{
|
|
DBUG_ENTER("bitmap_free");
|
|
if (map->bitmap)
|
|
{
|
|
#ifdef THREAD
|
|
if (map->mutex)
|
|
pthread_mutex_destroy(map->mutex);
|
|
#endif
|
|
my_free((char*) map->bitmap, MYF(0));
|
|
map->bitmap=0;
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit)
|
|
{
|
|
DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
|
|
bitmap_lock(map);
|
|
bitmap_fast_set_bit(map, bitmap_bit);
|
|
bitmap_unlock(map);
|
|
}
|
|
|
|
|
|
uint bitmap_set_next(MY_BITMAP *map)
|
|
{
|
|
uchar *bitmap=map->bitmap;
|
|
uint bit_found = MY_BIT_NONE;
|
|
uint bitmap_size=map->bitmap_size;
|
|
uint i;
|
|
|
|
DBUG_ASSERT(map->bitmap);
|
|
bitmap_lock(map);
|
|
for (i=0; i < bitmap_size ; i++, bitmap++)
|
|
{
|
|
if (*bitmap != 0xff)
|
|
{ /* Found slot with free bit */
|
|
uint b;
|
|
for (b=0; ; b++)
|
|
{
|
|
if (!(*bitmap & (1 << b)))
|
|
{
|
|
*bitmap |= 1<<b;
|
|
bit_found = (i*8)+b;
|
|
break;
|
|
}
|
|
}
|
|
break; /* Found bit */
|
|
}
|
|
}
|
|
bitmap_unlock(map);
|
|
return bit_found;
|
|
}
|
|
|
|
|
|
void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit)
|
|
{
|
|
DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
|
|
bitmap_lock(map);
|
|
bitmap_fast_clear_bit(map, bitmap_bit);
|
|
bitmap_unlock(map);
|
|
}
|
|
|
|
|
|
void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
|
|
{
|
|
uint prefix_bytes, prefix_bits;
|
|
|
|
DBUG_ASSERT(map->bitmap &&
|
|
(prefix_size <= map->bitmap_size*8 || prefix_size == (uint) ~0));
|
|
bitmap_lock(map);
|
|
set_if_smaller(prefix_size, map->bitmap_size*8);
|
|
if ((prefix_bytes= prefix_size / 8))
|
|
memset(map->bitmap, 0xff, prefix_bytes);
|
|
if ((prefix_bits= prefix_size & 7))
|
|
map->bitmap[prefix_bytes++]= (1 << prefix_bits)-1;
|
|
if (prefix_bytes < map->bitmap_size)
|
|
bzero(map->bitmap+prefix_bytes, map->bitmap_size-prefix_bytes);
|
|
bitmap_unlock(map);
|
|
}
|
|
|
|
|
|
void bitmap_clear_all(MY_BITMAP *map)
|
|
{
|
|
bitmap_set_prefix(map, 0);
|
|
}
|
|
|
|
|
|
void bitmap_set_all(MY_BITMAP *map)
|
|
{
|
|
bitmap_set_prefix(map, ~0);
|
|
}
|
|
|
|
|
|
my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size)
|
|
{
|
|
uint prefix_bits= prefix_size & 7, res= 0;
|
|
uchar *m= map->bitmap, *end_prefix= map->bitmap+prefix_size/8,
|
|
*end= map->bitmap+map->bitmap_size;
|
|
|
|
DBUG_ASSERT(map->bitmap && prefix_size <= map->bitmap_size*8);
|
|
|
|
bitmap_lock((MY_BITMAP *)map);
|
|
while (m < end_prefix)
|
|
if (*m++ != 0xff)
|
|
goto ret;
|
|
|
|
if (prefix_bits && *m++ != (1 << prefix_bits)-1)
|
|
goto ret;
|
|
|
|
while (m < end)
|
|
if (*m++ != 0)
|
|
goto ret;
|
|
|
|
res=1;
|
|
ret:
|
|
bitmap_unlock((MY_BITMAP *)map);
|
|
return res;
|
|
}
|
|
|
|
|
|
my_bool bitmap_is_clear_all(const MY_BITMAP *map)
|
|
{
|
|
return bitmap_is_prefix(map, 0);
|
|
}
|
|
|
|
my_bool bitmap_is_set_all(const MY_BITMAP *map)
|
|
{
|
|
return bitmap_is_prefix(map, map->bitmap_size*8);
|
|
}
|
|
|
|
|
|
my_bool bitmap_is_set(const MY_BITMAP *map, uint bitmap_bit)
|
|
{
|
|
DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
|
|
return bitmap_fast_is_set(map, bitmap_bit);
|
|
}
|
|
|
|
|
|
my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2)
|
|
{
|
|
uint res=0;
|
|
uchar *m1=map1->bitmap, *m2=map2->bitmap, *end;
|
|
|
|
DBUG_ASSERT(map1->bitmap && map2->bitmap &&
|
|
map1->bitmap_size==map2->bitmap_size);
|
|
bitmap_lock((MY_BITMAP *)map1);
|
|
bitmap_lock((MY_BITMAP *)map2);
|
|
|
|
end= m1+map1->bitmap_size;
|
|
|
|
while (m1 < end)
|
|
{
|
|
if ((*m1++) & ~(*m2++))
|
|
goto ret;
|
|
}
|
|
|
|
res=1;
|
|
ret:
|
|
bitmap_unlock((MY_BITMAP *)map2);
|
|
bitmap_unlock((MY_BITMAP *)map1);
|
|
return res;
|
|
}
|
|
|
|
|
|
my_bool bitmap_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2)
|
|
{
|
|
uint res;
|
|
|
|
DBUG_ASSERT(map1->bitmap && map2->bitmap &&
|
|
map1->bitmap_size==map2->bitmap_size);
|
|
bitmap_lock((MY_BITMAP *)map1);
|
|
bitmap_lock((MY_BITMAP *)map2);
|
|
|
|
res= memcmp(map1->bitmap, map2->bitmap, map1->bitmap_size)==0;
|
|
|
|
bitmap_unlock((MY_BITMAP *)map2);
|
|
bitmap_unlock((MY_BITMAP *)map1);
|
|
return res;
|
|
}
|
|
|
|
|
|
void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
|
|
{
|
|
uchar *to=map->bitmap, *from=map2->bitmap, *end;
|
|
uint len=map->bitmap_size, len2=map2->bitmap_size;
|
|
|
|
DBUG_ASSERT(map->bitmap && map2->bitmap);
|
|
bitmap_lock(map);
|
|
bitmap_lock((MY_BITMAP *)map2);
|
|
|
|
end= to+min(len,len2);
|
|
|
|
while (to < end)
|
|
*to++ &= *from++;
|
|
|
|
if (len2 < len)
|
|
{
|
|
end+=len-len2;
|
|
while (to < end)
|
|
*to++=0;
|
|
}
|
|
|
|
bitmap_unlock((MY_BITMAP *)map2);
|
|
bitmap_unlock(map);
|
|
}
|
|
|
|
|
|
void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2)
|
|
{
|
|
uchar *to=map->bitmap, *from=map2->bitmap, *end;
|
|
|
|
DBUG_ASSERT(map->bitmap && map2->bitmap &&
|
|
map->bitmap_size==map2->bitmap_size);
|
|
bitmap_lock(map);
|
|
bitmap_lock((MY_BITMAP *)map2);
|
|
|
|
end= to+map->bitmap_size;
|
|
|
|
while (to < end)
|
|
*to++ &= ~(*from++);
|
|
|
|
bitmap_unlock((MY_BITMAP *)map2);
|
|
bitmap_unlock(map);
|
|
}
|
|
|
|
|
|
void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
|
|
{
|
|
uchar *to=map->bitmap, *from=map2->bitmap, *end;
|
|
|
|
DBUG_ASSERT(map->bitmap && map2->bitmap &&
|
|
map->bitmap_size==map2->bitmap_size);
|
|
bitmap_lock(map);
|
|
bitmap_lock((MY_BITMAP *)map2);
|
|
|
|
end= to+map->bitmap_size;
|
|
|
|
while (to < end)
|
|
*to++ |= *from++;
|
|
|
|
bitmap_unlock((MY_BITMAP *)map2);
|
|
bitmap_unlock(map);
|
|
}
|
|
|