Commit 2c44ef17 authored by unknown's avatar unknown

Fixed BUG#10968: Stored procedures: crash if long loop

  Free memory after all SP invokation.


sql/sp_head.cc:
  Fixed memory leaks in SP invokation. Have to release memory after each call,
  or items and contexts are not released until it's too late.
parent 29f3b76f
......@@ -696,6 +696,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
sp_rcontext *nctx = NULL;
uint i;
int ret;
MEM_ROOT *old_mem_root, call_mem_root;
Item *old_free_list, *call_free_list;
if (argcount != params)
{
......@@ -706,6 +708,12 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
DBUG_RETURN(-1);
}
init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
old_mem_root= thd->mem_root;
thd->mem_root= &call_mem_root;
old_free_list= thd->free_list; // Keep the old list
thd->free_list= NULL; // Start a new one
// QQ Should have some error checking here? (types, etc...)
nctx= new sp_rcontext(csize, hmax, cmax);
for (i= 0 ; i < params && i < argcount ; i++)
......@@ -736,13 +744,20 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
ret= execute(thd);
// Partially restore context now.
// We still need the call mem root and free list for processing
// of the result.
call_free_list= thd->free_list;
thd->free_list= old_free_list;
thd->mem_root= old_mem_root;
if (m_type == TYPE_ENUM_FUNCTION && ret == 0)
{
/* We need result only in function but not in trigger */
Item *it= nctx->get_result();
if (it)
*resp= it;
*resp= sp_eval_func_item(thd, &it, m_returns, NULL);
else
{
my_error(ER_SP_NORETURNEND, MYF(0), m_name.str);
......@@ -752,6 +767,12 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
nctx->pop_all_cursors(); // To avoid memory leaks after an error
thd->spcont= octx;
// Now get rid of the rest of the callee context
cleanup_items(call_free_list);
free_items(call_free_list);
free_root(&call_mem_root, MYF(0));
DBUG_RETURN(ret);
}
......@@ -781,6 +802,8 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
sp_rcontext *octx = thd->spcont;
sp_rcontext *nctx = NULL;
my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx
MEM_ROOT *old_mem_root, call_mem_root;
Item *old_free_list, *call_free_list;
if (args->elements != params)
{
......@@ -789,6 +812,12 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
DBUG_RETURN(-1);
}
init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
old_mem_root= thd->mem_root;
thd->mem_root= &call_mem_root;
old_free_list= thd->free_list; // Keep the old list
thd->free_list= NULL; // Start a new one
if (csize > 0 || hmax > 0 || cmax > 0)
{
Item_null *nit= NULL; // Re-use this, and only create if needed
......@@ -854,9 +883,16 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (! ret)
ret= execute(thd);
// Partially restore context now.
// We still need the call mem root and free list for processing
// of out parameters.
call_free_list= thd->free_list;
thd->free_list= old_free_list;
thd->mem_root= old_mem_root;
if (!ret && csize > 0)
{
List_iterator_fast<Item> li(*args);
List_iterator<Item> li(*args);
Item *it;
// Copy back all OUT or INOUT values to the previous frame, or
......@@ -868,8 +904,34 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (pvar->mode != sp_param_in)
{
if (it->is_splocal())
octx->set_item(static_cast<Item_splocal *>(it)->get_offset(),
nctx->get_item(i));
{
// Have to copy the item to the caller's mem_root
Item *copy;
uint offset= static_cast<Item_splocal *>(it)->get_offset();
Item *val= nctx->get_item(i);
Item *orig= octx->get_item(offset);
Item *o_item_next;
Item *o_free_list= thd->free_list;
LINT_INIT(o_item_next);
if (orig)
o_item_next= orig->next;
copy= sp_eval_func_item(thd, &val, pvar->type, orig); // Copy
if (!copy)
{
ret= -1;
break;
}
if (copy != orig)
octx->set_item(offset, copy);
if (orig && copy == orig)
{
// A reused item slot, where the constructor put it in the
// free_list, so we have to restore the list.
thd->free_list= o_free_list;
copy->next= o_item_next;
}
}
else
{
Item_func_get_user_var *guv= item_is_user_var(it);
......@@ -900,6 +962,11 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
nctx->pop_all_cursors(); // To avoid memory leaks after an error
thd->spcont= octx;
// Now get rid of the rest of the callee context
cleanup_items(call_free_list);
free_items(call_free_list);
free_root(&call_mem_root, MYF(0));
DBUG_RETURN(ret);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment