Commit c3dc1d6d 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 4f597b14
......@@ -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)
{
if (thd == entry_thd && entry)
if (entry && thd->thread_id == entry_thread_id)
goto end; // update entry->update_query_id for PS
entry_thd= thd;
if (!(entry= get_variable(&thd->user_vars, name, create_if_not_exists)))
{
entry_thread_id= 0;
return TRUE;
}
entry_thread_id= thd->thread_id;
/*
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
......
......@@ -1295,16 +1295,16 @@ class Item_func_set_user_var :public Item_func
enum Item_result cached_result_type;
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);
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
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
connection calling the same trigger that initially updated some
user variable it the first connection context).
*/
THD *entry_thd;
my_thread_id entry_thread_id;
char buffer[MAX_FIELD_WIDTH];
String value;
my_decimal decimal_buff;
......@@ -1321,7 +1321,7 @@ public:
LEX_STRING name; // keep it public
Item_func_set_user_var(LEX_STRING a,Item *b)
: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; }
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