mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Fixed BUG#16887: Cursor causes server segfault
The problem was a code generation bug: cpop instructions were not generated when using ITERATE back to an outer block from a context with a declared cursor; this would make it push a new cursor without popping in-between, eventually overrunning the cursor stack with a crash as the result. Fixed the calculation of how many cursors to pop (in sp_pcontext.cc: diff_cursors()), and also corrected diff_cursors() and diff_handlers() to when doing a "leave"; don't include the last context we're leaving (we are then jumping to the appropriate pop instructions).
This commit is contained in:
@ -4519,4 +4519,60 @@ Handler
|
|||||||
Inner
|
Inner
|
||||||
drop procedure bug15011|
|
drop procedure bug15011|
|
||||||
drop table t3|
|
drop table t3|
|
||||||
|
drop table if exists t3|
|
||||||
|
drop procedure if exists bug16887|
|
||||||
|
create table t3 ( c varchar(1) )|
|
||||||
|
insert into t3 values
|
||||||
|
(' '),('.'),(';'),(','),('-'),('_'),('('),(')'),('/'),('\\')|
|
||||||
|
create procedure bug16887()
|
||||||
|
begin
|
||||||
|
declare i int default 10;
|
||||||
|
again:
|
||||||
|
while i > 0 do
|
||||||
|
begin
|
||||||
|
declare breakchar varchar(1);
|
||||||
|
declare done int default 0;
|
||||||
|
declare t3_cursor cursor for select c from t3;
|
||||||
|
declare continue handler for not found set done = 1;
|
||||||
|
set i = i - 1;
|
||||||
|
select i;
|
||||||
|
if i = 3 then
|
||||||
|
iterate again;
|
||||||
|
end if;
|
||||||
|
open t3_cursor;
|
||||||
|
loop
|
||||||
|
fetch t3_cursor into breakchar;
|
||||||
|
if done = 1 then
|
||||||
|
begin
|
||||||
|
close t3_cursor;
|
||||||
|
iterate again;
|
||||||
|
end;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
end;
|
||||||
|
end while;
|
||||||
|
end|
|
||||||
|
call bug16887()|
|
||||||
|
i
|
||||||
|
9
|
||||||
|
i
|
||||||
|
8
|
||||||
|
i
|
||||||
|
7
|
||||||
|
i
|
||||||
|
6
|
||||||
|
i
|
||||||
|
5
|
||||||
|
i
|
||||||
|
4
|
||||||
|
i
|
||||||
|
3
|
||||||
|
i
|
||||||
|
2
|
||||||
|
i
|
||||||
|
1
|
||||||
|
i
|
||||||
|
0
|
||||||
|
drop table t3|
|
||||||
|
drop procedure bug16887|
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
|
@ -5311,6 +5311,60 @@ drop procedure bug15011|
|
|||||||
drop table t3|
|
drop table t3|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# BUG#16887: Cursor causes server segfault
|
||||||
|
#
|
||||||
|
--disable_warnings
|
||||||
|
drop table if exists t3|
|
||||||
|
drop procedure if exists bug16887|
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
create table t3 ( c varchar(1) )|
|
||||||
|
|
||||||
|
insert into t3 values
|
||||||
|
(' '),('.'),(';'),(','),('-'),('_'),('('),(')'),('/'),('\\')|
|
||||||
|
|
||||||
|
create procedure bug16887()
|
||||||
|
begin
|
||||||
|
declare i int default 10;
|
||||||
|
|
||||||
|
again:
|
||||||
|
while i > 0 do
|
||||||
|
begin
|
||||||
|
declare breakchar varchar(1);
|
||||||
|
declare done int default 0;
|
||||||
|
declare t3_cursor cursor for select c from t3;
|
||||||
|
declare continue handler for not found set done = 1;
|
||||||
|
|
||||||
|
set i = i - 1;
|
||||||
|
select i;
|
||||||
|
|
||||||
|
if i = 3 then
|
||||||
|
iterate again;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
open t3_cursor;
|
||||||
|
|
||||||
|
loop
|
||||||
|
fetch t3_cursor into breakchar;
|
||||||
|
|
||||||
|
if done = 1 then
|
||||||
|
begin
|
||||||
|
close t3_cursor;
|
||||||
|
iterate again;
|
||||||
|
end;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
end;
|
||||||
|
end while;
|
||||||
|
end|
|
||||||
|
|
||||||
|
call bug16887()|
|
||||||
|
|
||||||
|
drop table t3|
|
||||||
|
drop procedure bug16887|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# BUG#NNNN: New bug synopsis
|
# BUG#NNNN: New bug synopsis
|
||||||
#
|
#
|
||||||
|
@ -122,30 +122,38 @@ sp_pcontext::pop_context()
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint
|
uint
|
||||||
sp_pcontext::diff_handlers(sp_pcontext *ctx)
|
sp_pcontext::diff_handlers(sp_pcontext *ctx, bool exclusive)
|
||||||
{
|
{
|
||||||
uint n= 0;
|
uint n= 0;
|
||||||
sp_pcontext *pctx= this;
|
sp_pcontext *pctx= this;
|
||||||
|
sp_pcontext *last_ctx= NULL;
|
||||||
|
|
||||||
while (pctx && pctx != ctx)
|
while (pctx && pctx != ctx)
|
||||||
{
|
{
|
||||||
n+= pctx->m_handlers;
|
n+= pctx->m_handlers;
|
||||||
|
last_ctx= pctx;
|
||||||
pctx= pctx->parent_context();
|
pctx= pctx->parent_context();
|
||||||
}
|
}
|
||||||
if (pctx)
|
if (pctx)
|
||||||
return n;
|
return (exclusive && last_ctx ? n - last_ctx->m_handlers : n);
|
||||||
return 0; // Didn't find ctx
|
return 0; // Didn't find ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
uint
|
uint
|
||||||
sp_pcontext::diff_cursors(sp_pcontext *ctx)
|
sp_pcontext::diff_cursors(sp_pcontext *ctx, bool exclusive)
|
||||||
{
|
{
|
||||||
|
uint n= 0;
|
||||||
sp_pcontext *pctx= this;
|
sp_pcontext *pctx= this;
|
||||||
|
sp_pcontext *last_ctx= NULL;
|
||||||
|
|
||||||
while (pctx && pctx != ctx)
|
while (pctx && pctx != ctx)
|
||||||
|
{
|
||||||
|
n+= pctx->m_cursor.elements;
|
||||||
|
last_ctx= pctx;
|
||||||
pctx= pctx->parent_context();
|
pctx= pctx->parent_context();
|
||||||
|
}
|
||||||
if (pctx)
|
if (pctx)
|
||||||
return ctx->current_cursors() - pctx->current_cursors();
|
return (exclusive && last_ctx ? n - last_ctx->m_cursor.elements : n);
|
||||||
return 0; // Didn't find ctx
|
return 0; // Didn't find ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,11 +119,15 @@ class sp_pcontext : public Sql_alloc
|
|||||||
return m_parent;
|
return m_parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Number of handlers/cursors to pop between this context and 'ctx'.
|
||||||
|
If 'exclusive' is true, don't count the last block we are leaving;
|
||||||
|
this is used for LEAVE where we will jump to the cpop/hpop instructions.
|
||||||
|
*/
|
||||||
uint
|
uint
|
||||||
diff_handlers(sp_pcontext *ctx);
|
diff_handlers(sp_pcontext *ctx, bool exclusive);
|
||||||
|
|
||||||
uint
|
uint
|
||||||
diff_cursors(sp_pcontext *ctx);
|
diff_cursors(sp_pcontext *ctx, bool exclusive);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -2079,10 +2079,10 @@ sp_proc_stmt:
|
|||||||
uint ip= sp->instructions();
|
uint ip= sp->instructions();
|
||||||
uint n;
|
uint n;
|
||||||
|
|
||||||
n= ctx->diff_handlers(lab->ctx);
|
n= ctx->diff_handlers(lab->ctx, TRUE); /* Exclusive the dest. */
|
||||||
if (n)
|
if (n)
|
||||||
sp->add_instr(new sp_instr_hpop(ip++, ctx, n));
|
sp->add_instr(new sp_instr_hpop(ip++, ctx, n));
|
||||||
n= ctx->diff_cursors(lab->ctx);
|
n= ctx->diff_cursors(lab->ctx, TRUE); /* Exclusive the dest. */
|
||||||
if (n)
|
if (n)
|
||||||
sp->add_instr(new sp_instr_cpop(ip++, ctx, n));
|
sp->add_instr(new sp_instr_cpop(ip++, ctx, n));
|
||||||
i= new sp_instr_jump(ip, ctx);
|
i= new sp_instr_jump(ip, ctx);
|
||||||
@ -2108,10 +2108,10 @@ sp_proc_stmt:
|
|||||||
uint ip= sp->instructions();
|
uint ip= sp->instructions();
|
||||||
uint n;
|
uint n;
|
||||||
|
|
||||||
n= ctx->diff_handlers(lab->ctx);
|
n= ctx->diff_handlers(lab->ctx, FALSE); /* Inclusive the dest. */
|
||||||
if (n)
|
if (n)
|
||||||
sp->add_instr(new sp_instr_hpop(ip++, ctx, n));
|
sp->add_instr(new sp_instr_hpop(ip++, ctx, n));
|
||||||
n= ctx->diff_cursors(lab->ctx);
|
n= ctx->diff_cursors(lab->ctx, FALSE); /* Inclusive the dest. */
|
||||||
if (n)
|
if (n)
|
||||||
sp->add_instr(new sp_instr_cpop(ip++, ctx, n));
|
sp->add_instr(new sp_instr_cpop(ip++, ctx, n));
|
||||||
i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */
|
i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */
|
||||||
|
Reference in New Issue
Block a user