Commit 0ff8074f authored by Ramil Kalimullin's avatar Ramil Kalimullin

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.
parent f63a8a07
...@@ -3810,11 +3810,14 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, ...@@ -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 ...@@ -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 @@ class Item_func_set_user_var :public Item_func ...@@ -1321,7 +1321,7 @@ class Item_func_set_user_var :public Item_func
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();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment