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:
Ramil Kalimullin 2008-11-20 15:25:26 +04:00
parent 4f597b14a8
commit c3dc1d6dfb
2 changed files with 9 additions and 6 deletions

View File

@ -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

View File

@ -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();