From febe03c2dbc3b9cab4f7e083274619f6bb96ec4a Mon Sep 17 00:00:00 2001 From: Ahmad Abdullateef Date: Tue, 18 Dec 2012 22:12:56 +0530 Subject: [PATCH] BUG#14727815 - CRASH IN PTHREAD_RWLOCK_WRLOCK/SRW_UNLOCK IN QUERY CACHE CODE DESCRIPTION: MySQL Server crashes sporadically when Query Caching is on and the server has high contention among clients. ANALYSIS : Scenario 1: In Query_cache::move_by_type() when handling RESULT or its related blocks, Write Lock is acquired on its parent Query block. However the next and prev pointers are cached in local variables before lock acquisition. In an extremely high contention scenario there exists a possibility that Query_cache::append_result_data() is operating on the same query block and as a consequence might append a new Result block to the end of Result blocks Linked List of the Query. This would manipulate the next, prev pointers of the Block being processed in move_by_type(), however the local pointers still point to previous nodes there by causing Data Corruption leading to crash. FIX : Scenario 1: The next, prev pointers are now accessed only after Lock acquisition in Query_cache::move_by_type(). --- sql/sql_cache.cc | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 8056ca6b49f..cba7c876a4c 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -3892,15 +3892,14 @@ my_bool Query_cache::move_by_type(uchar **border, case Query_cache_block::RES_CONT: case Query_cache_block::RESULT: { - DBUG_PRINT("qcache", ("block 0x%lx RES* (%d)", (ulong) block, - (int) block->type)); - if (*border == 0) - break; - Query_cache_block *query_block = block->result()->parent(), - *next = block->next, - *prev = block->prev; - Query_cache_block::block_type type = block->type; - BLOCK_LOCK_WR(query_block); + DBUG_PRINT("qcache", ("block 0x%lx RES* (%d)", (ulong) block, + (int) block->type)); + if (*border == 0) + break; + Query_cache_block *query_block= block->result()->parent(); + BLOCK_LOCK_WR(query_block); + Query_cache_block *next= block->next, *prev= block->prev; + Query_cache_block::block_type type= block->type; ulong len = block->length, used = block->used; Query_cache_block *pprev = block->pprev, *pnext = block->pnext,