mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
MDEV-40639 Open SYS_REFCURSOR crash, if many cursors inside a function
Problem: If: - A routine A() opened a SYS_REFCURSOR with a function B() in the SELECT list - The function B() also opened some SYS_REFCURSORs Then reallocation of the cursor array THD::m_statement_cursors could happen during the execution of B(), so all sp_cursor_array_element pointers inside sp_instr_copen_by_ref::exec_core() of routine A() became invalid. Fix: Chaging the data type of sp_cursor_array: - from Dynamic_array<sp_cursor_array_element> - to Dynamic_array<sp_cursor_array_element*> So now only reallocations of the array of cursor pointers happen, while sp_cursor_array_element instances always stay on their originally allocated memory positions. Note: sp_cursor_array_element instances are allocated using the standart C++ "new" and deleted using the standard C++ "delete". Using a MEM_ROOT does not seem to be relevant here.
This commit is contained in:
@@ -442,3 +442,56 @@ END$
|
||||
a
|
||||
116
|
||||
SET @@max_open_cursors = DEFAULT;
|
||||
#
|
||||
# MDEV-40639 Open SYS_REFCURSOR crash, if many cursors inside a function
|
||||
#
|
||||
CREATE FUNCTION trigger_realloc() RETURNS INT
|
||||
BEGIN
|
||||
DECLARE c1 SYS_REFCURSOR;
|
||||
DECLARE c2 SYS_REFCURSOR;
|
||||
DECLARE c3 SYS_REFCURSOR;
|
||||
DECLARE c4 SYS_REFCURSOR;
|
||||
DECLARE c5 SYS_REFCURSOR;
|
||||
DECLARE c6 SYS_REFCURSOR;
|
||||
DECLARE c7 SYS_REFCURSOR;
|
||||
DECLARE c8 SYS_REFCURSOR;
|
||||
DECLARE c9 SYS_REFCURSOR;
|
||||
DECLARE c10 SYS_REFCURSOR;
|
||||
DECLARE c11 SYS_REFCURSOR;
|
||||
DECLARE c12 SYS_REFCURSOR;
|
||||
DECLARE c13 SYS_REFCURSOR;
|
||||
DECLARE c14 SYS_REFCURSOR;
|
||||
DECLARE c15 SYS_REFCURSOR;
|
||||
DECLARE c16 SYS_REFCURSOR;
|
||||
DECLARE c17 SYS_REFCURSOR;
|
||||
OPEN c1 FOR SELECT 1;
|
||||
OPEN c2 FOR SELECT 1;
|
||||
OPEN c3 FOR SELECT 1;
|
||||
OPEN c4 FOR SELECT 1;
|
||||
OPEN c5 FOR SELECT 1;
|
||||
OPEN c6 FOR SELECT 1;
|
||||
OPEN c7 FOR SELECT 1;
|
||||
OPEN c8 FOR SELECT 1;
|
||||
OPEN c9 FOR SELECT 1;
|
||||
OPEN c10 FOR SELECT 1;
|
||||
OPEN c11 FOR SELECT 1;
|
||||
OPEN c12 FOR SELECT 1;
|
||||
OPEN c13 FOR SELECT 1;
|
||||
OPEN c14 FOR SELECT 1;
|
||||
OPEN c15 FOR SELECT 1;
|
||||
OPEN c16 FOR SELECT 1;
|
||||
OPEN c17 FOR SELECT 1;
|
||||
RETURN 1;
|
||||
END;
|
||||
$$
|
||||
CREATE PROCEDURE trigger_uaf()
|
||||
BEGIN
|
||||
DECLARE c SYS_REFCURSOR;
|
||||
OPEN c FOR SELECT trigger_realloc();
|
||||
END;
|
||||
$$
|
||||
SET SESSION max_open_cursors= 100;
|
||||
CALL trigger_uaf();
|
||||
SET SESSION max_open_cursors= DEFAULT;
|
||||
DROP PROCEDURE trigger_uaf;
|
||||
DROP FUNCTION trigger_realloc;
|
||||
|
||||
@@ -466,3 +466,64 @@ BEGIN NOT ATOMIC
|
||||
END$
|
||||
delimiter ;$
|
||||
SET @@max_open_cursors = DEFAULT;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-40639 Open SYS_REFCURSOR crash, if many cursors inside a function
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
# Function that forces cursor array reallocation (17 > default 16 slots)
|
||||
CREATE FUNCTION trigger_realloc() RETURNS INT
|
||||
BEGIN
|
||||
DECLARE c1 SYS_REFCURSOR;
|
||||
DECLARE c2 SYS_REFCURSOR;
|
||||
DECLARE c3 SYS_REFCURSOR;
|
||||
DECLARE c4 SYS_REFCURSOR;
|
||||
DECLARE c5 SYS_REFCURSOR;
|
||||
DECLARE c6 SYS_REFCURSOR;
|
||||
DECLARE c7 SYS_REFCURSOR;
|
||||
DECLARE c8 SYS_REFCURSOR;
|
||||
DECLARE c9 SYS_REFCURSOR;
|
||||
DECLARE c10 SYS_REFCURSOR;
|
||||
DECLARE c11 SYS_REFCURSOR;
|
||||
DECLARE c12 SYS_REFCURSOR;
|
||||
DECLARE c13 SYS_REFCURSOR;
|
||||
DECLARE c14 SYS_REFCURSOR;
|
||||
DECLARE c15 SYS_REFCURSOR;
|
||||
DECLARE c16 SYS_REFCURSOR;
|
||||
DECLARE c17 SYS_REFCURSOR;
|
||||
OPEN c1 FOR SELECT 1;
|
||||
OPEN c2 FOR SELECT 1;
|
||||
OPEN c3 FOR SELECT 1;
|
||||
OPEN c4 FOR SELECT 1;
|
||||
OPEN c5 FOR SELECT 1;
|
||||
OPEN c6 FOR SELECT 1;
|
||||
OPEN c7 FOR SELECT 1;
|
||||
OPEN c8 FOR SELECT 1;
|
||||
OPEN c9 FOR SELECT 1;
|
||||
OPEN c10 FOR SELECT 1;
|
||||
OPEN c11 FOR SELECT 1;
|
||||
OPEN c12 FOR SELECT 1;
|
||||
OPEN c13 FOR SELECT 1;
|
||||
OPEN c14 FOR SELECT 1;
|
||||
OPEN c15 FOR SELECT 1;
|
||||
OPEN c16 FOR SELECT 1;
|
||||
OPEN c17 FOR SELECT 1;
|
||||
RETURN 1;
|
||||
END;
|
||||
$$
|
||||
|
||||
CREATE PROCEDURE trigger_uaf()
|
||||
BEGIN
|
||||
DECLARE c SYS_REFCURSOR;
|
||||
OPEN c FOR SELECT trigger_realloc();
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
SET SESSION max_open_cursors= 100;
|
||||
CALL trigger_uaf();
|
||||
SET SESSION max_open_cursors= DEFAULT;
|
||||
DROP PROCEDURE trigger_uaf;
|
||||
DROP FUNCTION trigger_realloc;
|
||||
|
||||
@@ -48,8 +48,11 @@ bool sp_cursor::check_for_open(THD *thd, bool check_open_cursor_counter) const
|
||||
*/
|
||||
Type_ref_null sp_cursor_array::append(THD *thd)
|
||||
{
|
||||
if (Dynamic_array::append(sp_cursor_array_element()))
|
||||
sp_cursor_array_element *elem= new sp_cursor_array_element();
|
||||
if (!elem || Dynamic_array::append(elem))
|
||||
{
|
||||
if (!elem)
|
||||
my_error(ER_OUTOFMEMORY, MYF(0), (int) sizeof(sp_cursor_array_element));
|
||||
DBUG_ASSERT(thd->is_error());
|
||||
return Type_ref_null();
|
||||
}
|
||||
@@ -70,7 +73,7 @@ sp_cursor_array_element *sp_cursor_array::get_cursor_by_ref(THD *thd,
|
||||
{
|
||||
Type_ref_null ref= ref_field->val_ref(thd);
|
||||
if (ref < (ulonglong) elements())
|
||||
return &at((size_t) ref.value());// "ref" points to an initialized sp_cursor
|
||||
return at((size_t) ref.value());// "ref" points to an initialized sp_cursor
|
||||
|
||||
if (!for_open)
|
||||
return nullptr;
|
||||
@@ -88,8 +91,8 @@ sp_cursor_array_element *sp_cursor_array::get_cursor_by_ref(THD *thd,
|
||||
ref_field->store_ref(ref, true/*no_conversions*/))
|
||||
return nullptr;
|
||||
|
||||
at((size_t) ref.value()).reset(thd, 1/*ref count*/);
|
||||
return &at((size_t) ref.value());
|
||||
at((size_t) ref.value())->reset(thd, 1/*ref count*/);
|
||||
return at((size_t) ref.value());
|
||||
}
|
||||
|
||||
#endif // MYSQL_SERVER
|
||||
|
||||
@@ -193,14 +193,14 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class sp_cursor_array: public Dynamic_array<sp_cursor_array_element>
|
||||
class sp_cursor_array: public Dynamic_array<sp_cursor_array_element*>
|
||||
{
|
||||
protected:
|
||||
Type_ref_null find_unused()
|
||||
{
|
||||
for (size_t i= 0 ; i < size(); i++)
|
||||
{
|
||||
if (!at(i).is_open() && !at(i).ref_count())
|
||||
if (!at(i)->is_open() && !at(i)->ref_count())
|
||||
return Type_ref_null((ulonglong) i);
|
||||
}
|
||||
return Type_ref_null();
|
||||
@@ -220,20 +220,20 @@ public:
|
||||
ULonglong_null ref_count(ulonglong offset) const
|
||||
{
|
||||
return offset < elements() ?
|
||||
ULonglong_null((ulonglong) at((size_t) offset).ref_count()) :
|
||||
ULonglong_null((ulonglong) at((size_t) offset)->ref_count()) :
|
||||
ULonglong_null();
|
||||
}
|
||||
|
||||
void ref_count_inc(ulonglong offset)
|
||||
{
|
||||
if (offset < elements())
|
||||
at((size_t) offset).ref_count_inc();
|
||||
at((size_t) offset)->ref_count_inc();
|
||||
}
|
||||
|
||||
void ref_count_dec(THD *thd, ulonglong offset)
|
||||
{
|
||||
if (offset < elements())
|
||||
at((size_t) offset).ref_count_dec(thd);
|
||||
at((size_t) offset)->ref_count_dec(thd);
|
||||
}
|
||||
|
||||
void ref_count_update(THD *thd, const Type_ref_null &old_value,
|
||||
@@ -281,13 +281,18 @@ public:
|
||||
{
|
||||
for (uint i= 0; i < (uint) size(); i++)
|
||||
{
|
||||
if (at(i).is_open())
|
||||
at(i).close(thd);
|
||||
if (at(i)->is_open())
|
||||
at(i)->close(thd);
|
||||
}
|
||||
}
|
||||
void free(THD *thd)
|
||||
{
|
||||
close(thd);
|
||||
for (uint i= 0; i < (uint) size(); i++)
|
||||
{
|
||||
DBUG_ASSERT(at(i));
|
||||
delete at(i);
|
||||
}
|
||||
free_memory();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -109,7 +109,7 @@ sp_cursor *Sp_rcontext_handler_local::get_cursor(THD *thd, uint offset) const
|
||||
|
||||
sp_cursor *Sp_rcontext_handler_statement::get_cursor(THD *thd, uint offset) const
|
||||
{
|
||||
return &thd->statement_cursors()->at(offset);
|
||||
return thd->statement_cursors()->at(offset);
|
||||
}
|
||||
|
||||
sp_cursor *Sp_rcontext_handler_statement::get_cursor_by_ref(THD *thd,
|
||||
|
||||
Reference in New Issue
Block a user