mirror of
https://github.com/MariaDB/server.git
synced 2025-01-19 05:22:25 +01:00
Fixed BUG#10968: Stored procedures: crash if long loop
Free memory after all SP invokation.
This commit is contained in:
parent
0d5e311176
commit
8c3b7accc7
1 changed files with 71 additions and 4 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue