Fix for bug#40770: Server Crash when running with triggers including
variable settings (rpl_sys) Problem: under certain conditions (e.g. user variables usage in triggers) accessing a user defined variable we may use a variables hash table that belongs to already deleted thread. It happens if thd= new THD; has the same address as just deleted thd as we use if (stored_thd == thd) to check. That may lead to unpredictable results, server crash etc. Fix: use thread_id instead of thd address to distinguish threads. Note: no simple and repeatable test case. sql/item_func.cc: Fix for bug#40770: Server Crash when running with triggers including variable settings (rpl_sys) - store and use thd->thread_id to distinguish threads instead of thread address as it may be the same as just deleted thread had, i.e. we may get (old_thd == new_thd) after delete old_thd; new_thd= new THD; - set entry_thread_id only when we get a real entry, clear it if the hash search fails. sql/item_func.h: Fix for bug#40770: Server Crash when running with triggers including variable settings (rpl_sys) - Item_func_set_user_var::entry_thread_id introduced.
This commit is contained in:
parent
4f597b14a8
commit
c3dc1d6dfb
@ -3810,11 +3810,14 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
|
|||||||
|
|
||||||
bool Item_func_set_user_var::set_entry(THD *thd, bool create_if_not_exists)
|
bool Item_func_set_user_var::set_entry(THD *thd, bool create_if_not_exists)
|
||||||
{
|
{
|
||||||
if (thd == entry_thd && entry)
|
if (entry && thd->thread_id == entry_thread_id)
|
||||||
goto end; // update entry->update_query_id for PS
|
goto end; // update entry->update_query_id for PS
|
||||||
entry_thd= thd;
|
|
||||||
if (!(entry= get_variable(&thd->user_vars, name, create_if_not_exists)))
|
if (!(entry= get_variable(&thd->user_vars, name, create_if_not_exists)))
|
||||||
|
{
|
||||||
|
entry_thread_id= 0;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
}
|
||||||
|
entry_thread_id= thd->thread_id;
|
||||||
/*
|
/*
|
||||||
Remember the last query which updated it, this way a query can later know
|
Remember the last query which updated it, this way a query can later know
|
||||||
if this variable is a constant item in the query (it is if update_query_id
|
if this variable is a constant item in the query (it is if update_query_id
|
||||||
|
@ -1295,16 +1295,16 @@ class Item_func_set_user_var :public Item_func
|
|||||||
enum Item_result cached_result_type;
|
enum Item_result cached_result_type;
|
||||||
user_var_entry *entry;
|
user_var_entry *entry;
|
||||||
/*
|
/*
|
||||||
The entry_thd variable is used:
|
The entry_thread_id variable is used:
|
||||||
1) to skip unnecessary updates of the entry field (see above);
|
1) to skip unnecessary updates of the entry field (see above);
|
||||||
2) to reset the entry field that was initialized in the other thread
|
2) to reset the entry field that was initialized in the other thread
|
||||||
(for example, an item tree of a trigger that updates user variables
|
(for example, an item tree of a trigger that updates user variables
|
||||||
may be shared between several connections, and the entry_thd field
|
may be shared between several connections, and the entry_thread_id field
|
||||||
prevents updates of one connection user variables from a concurrent
|
prevents updates of one connection user variables from a concurrent
|
||||||
connection calling the same trigger that initially updated some
|
connection calling the same trigger that initially updated some
|
||||||
user variable it the first connection context).
|
user variable it the first connection context).
|
||||||
*/
|
*/
|
||||||
THD *entry_thd;
|
my_thread_id entry_thread_id;
|
||||||
char buffer[MAX_FIELD_WIDTH];
|
char buffer[MAX_FIELD_WIDTH];
|
||||||
String value;
|
String value;
|
||||||
my_decimal decimal_buff;
|
my_decimal decimal_buff;
|
||||||
@ -1321,7 +1321,7 @@ public:
|
|||||||
LEX_STRING name; // keep it public
|
LEX_STRING name; // keep it public
|
||||||
Item_func_set_user_var(LEX_STRING a,Item *b)
|
Item_func_set_user_var(LEX_STRING a,Item *b)
|
||||||
:Item_func(b), cached_result_type(INT_RESULT),
|
:Item_func(b), cached_result_type(INT_RESULT),
|
||||||
entry(NULL), entry_thd(NULL), name(a)
|
entry(NULL), entry_thread_id(0), name(a)
|
||||||
{}
|
{}
|
||||||
enum Functype functype() const { return SUSERVAR_FUNC; }
|
enum Functype functype() const { return SUSERVAR_FUNC; }
|
||||||
double val_real();
|
double val_real();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user