Commit 1539b039 authored by unknown's avatar unknown
Browse files

Fix for #5730 (Query cache crashes server)

Recusive part leads to stack overflow


sql/sql_cache.cc:
  Recursion removed from Query_cache::allocate_data_chain
parent 99e3f21c
Loading
Loading
Loading
Loading
+37 −38
Original line number Diff line number Diff line
@@ -1843,7 +1843,6 @@ inline ulong Query_cache::get_min_append_result_data_size()
/*
  Allocate one or more blocks to hold data
*/

my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block,
					 ulong data_len,
					 Query_cache_block *query_block,
@@ -1851,55 +1850,55 @@ my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block,
{
  ulong all_headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) +
			   ALIGN_SIZE(sizeof(Query_cache_result)));
  ulong len= data_len + all_headers_len;
  ulong align_len= ALIGN_SIZE(len);
  ulong min_size = (first_block_arg ?
		    get_min_first_result_data_size():
		    get_min_append_result_data_size());
  Query_cache_block *prev_block= NULL;
  Query_cache_block *new_block;
  DBUG_ENTER("Query_cache::allocate_data_chain");
  DBUG_PRINT("qcache", ("data_len %lu, all_headers_len %lu",
			data_len, all_headers_len));

  ulong min_size = (first_block_arg ?
		    get_min_first_result_data_size():
		    get_min_append_result_data_size());
  *result_block = allocate_block(max(min_size, align_len),
  do
  {
    ulong len= data_len + all_headers_len;
    ulong align_len= ALIGN_SIZE(len);

    if (!(new_block= allocate_block(max(min_size, align_len),
				    min_result_data_size == 0,
				    all_headers_len + min_result_data_size,
				 1);
  my_bool success = (*result_block != 0);
  if (success)
				    1)))
    {
    Query_cache_block *new_block= *result_block;
      DBUG_PRINT("warning", ("Can't allocate block for results"));
      DBUG_RETURN(FALSE);
    }

    new_block->n_tables = 0;
    new_block->used = 0;
    new_block->used = min(len, new_block->length);
    new_block->type = Query_cache_block::RES_INCOMPLETE;
    new_block->next = new_block->prev = new_block;
    Query_cache_result *header = new_block->result();
    header->parent(query_block);

    if (new_block->length < len)
    {
    DBUG_PRINT("qcache", ("Block len %lu used %lu",
			  new_block->length, new_block->used));

    if (prev_block)
      double_linked_list_join(prev_block, new_block);
    else
      *result_block= new_block;
    if (new_block->length >= len)
      break;

    /*
      We got less memory then we need (no big memory blocks) =>
      Continue to allocated more blocks until we got everything we need.
    */
      Query_cache_block *next_block;
      if ((success = allocate_data_chain(&next_block,
					 len - new_block->length,
					 query_block, first_block_arg)))
	double_linked_list_join(new_block, next_block);
    }
    if (success)
    {
      new_block->used = min(len, new_block->length);
    data_len= len - new_block->length;
    prev_block= new_block;
  } while(1);

      DBUG_PRINT("qcache", ("Block len %lu used %lu",
			  new_block->length, new_block->used));
    }
    else
      DBUG_PRINT("warning", ("Can't allocate block for continue"));
  }
  else
    DBUG_PRINT("warning", ("Can't allocate block for results"));
  DBUG_RETURN(success);
  DBUG_RETURN(TRUE);
}

/*****************************************************************************