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
|
||||
drop procedure bug15011|
|
||||
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;
|
||||
|
@ -5311,6 +5311,60 @@ drop procedure bug15011|
|
||||
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
|
||||
#
|
||||
|
@ -122,30 +122,38 @@ sp_pcontext::pop_context()
|
||||
}
|
||||
|
||||
uint
|
||||
sp_pcontext::diff_handlers(sp_pcontext *ctx)
|
||||
sp_pcontext::diff_handlers(sp_pcontext *ctx, bool exclusive)
|
||||
{
|
||||
uint n= 0;
|
||||
sp_pcontext *pctx= this;
|
||||
sp_pcontext *last_ctx= NULL;
|
||||
|
||||
while (pctx && pctx != ctx)
|
||||
{
|
||||
n+= pctx->m_handlers;
|
||||
last_ctx= pctx;
|
||||
pctx= pctx->parent_context();
|
||||
}
|
||||
if (pctx)
|
||||
return n;
|
||||
return (exclusive && last_ctx ? n - last_ctx->m_handlers : n);
|
||||
return 0; // Didn't find ctx
|
||||
}
|
||||
|
||||
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 *last_ctx= NULL;
|
||||
|
||||
while (pctx && pctx != ctx)
|
||||
{
|
||||
n+= pctx->m_cursor.elements;
|
||||
last_ctx= pctx;
|
||||
pctx= pctx->parent_context();
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -119,11 +119,15 @@ class sp_pcontext : public Sql_alloc
|
||||
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
|
||||
diff_handlers(sp_pcontext *ctx);
|
||||
|
||||
diff_handlers(sp_pcontext *ctx, bool exclusive);
|
||||
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 n;
|
||||
|
||||
n= ctx->diff_handlers(lab->ctx);
|
||||
n= ctx->diff_handlers(lab->ctx, TRUE); /* Exclusive the dest. */
|
||||
if (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)
|
||||
sp->add_instr(new sp_instr_cpop(ip++, ctx, n));
|
||||
i= new sp_instr_jump(ip, ctx);
|
||||
@ -2108,10 +2108,10 @@ sp_proc_stmt:
|
||||
uint ip= sp->instructions();
|
||||
uint n;
|
||||
|
||||
n= ctx->diff_handlers(lab->ctx);
|
||||
n= ctx->diff_handlers(lab->ctx, FALSE); /* Inclusive the dest. */
|
||||
if (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)
|
||||
sp->add_instr(new sp_instr_cpop(ip++, ctx, n));
|
||||
i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */
|
||||
|
Reference in New Issue
Block a user