1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-27 18:02:13 +03:00

BUG#12589870 CRASHES WITH MULTIQUERY PACKET + USE<DB> + QUERY CACHE

A buffer large enough to hold the query _plus_ some additional
data is allocated before parsing is started.   The additional data 
is used by the query cache, and consists of the name of the current 
database and a set of flags.
 
When a packet containing multiple SQL statements is sent to the
server and one of the statements changes the current database
(a "USE <db>" statement), and the name of the new current database 
is longer than of the previous,  there is not enough space in the 
buffer for the new name, and we write out over the buffer boundary.

The fix adds an extra field to store the number of bytes
allocated to the database name in the buffer.  If the current
database name changes, and the new name is longer than the
previous one, we refuse to cache the query.
This commit is contained in:
Magne Mahre
2011-10-07 14:08:31 +02:00
parent 1922d65fd8
commit f36e854ac6
3 changed files with 58 additions and 8 deletions

View File

@ -1241,8 +1241,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
/* Key is query + database + flag */
if (thd->db_length)
{
memcpy(thd->query() + thd->query_length() + 1, thd->db,
thd->db_length);
memcpy(thd->query() + thd->query_length() + 1 + sizeof(size_t),
thd->db, thd->db_length);
DBUG_PRINT("qcache", ("database: %s length: %u",
thd->db, (unsigned) thd->db_length));
}
@ -1251,7 +1251,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
DBUG_PRINT("qcache", ("No active database"));
}
tot_length= thd->query_length() + thd->db_length + 1 +
QUERY_CACHE_FLAGS_SIZE;
sizeof(size_t) + QUERY_CACHE_FLAGS_SIZE;
/*
We should only copy structure (don't use it location directly)
because of alignment issue
@ -1462,7 +1462,28 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
goto err;
}
}
{
/*
We have allocated buffer space (in alloc_query) to hold the
SQL statement(s) + the current database name + a flags struct.
If the database name has changed during execution, which might
happen if there are multiple statements, we need to make
sure the new current database has a name with the same length
as the previous one.
*/
size_t *db_len= (size_t *) (sql + query_length + 1);
if (thd->db_length != *db_len)
{
/*
We should probably reallocate the buffer in this case,
but for now we just leave it uncached
*/
DBUG_PRINT("qcache",
("Current database has changed since start of query"));
goto err;
}
}
/*
Try to obtain an exclusive lock on the query cache. If the cache is
disabled or if a full cache flush is in progress, the attempt to
@ -1484,10 +1505,12 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
Query_cache_block *query_block;
tot_length= query_length + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE;
tot_length= query_length + 1 + sizeof(size_t) +
thd->db_length + QUERY_CACHE_FLAGS_SIZE;
if (thd->db_length)
{
memcpy(sql+query_length+1, thd->db, thd->db_length);
memcpy(sql + query_length + 1 + sizeof(size_t), thd->db, thd->db_length);
DBUG_PRINT("qcache", ("database: '%s' length: %u",
thd->db, (unsigned)thd->db_length));
}