diff options
author | Praveenkumar Hulakund <praveenkumar.hulakund@oracle.com> | 2012-11-07 19:08:33 +0530 |
---|---|---|
committer | Praveenkumar Hulakund <praveenkumar.hulakund@oracle.com> | 2012-11-07 19:08:33 +0530 |
commit | d912a758b02399c28cb30d97496ad5cdab35d214 (patch) | |
tree | 81c1dddbb0ffde40a0473341f3c2a1f8b07d62ac /sql/item_func.cc | |
parent | f5fbcfe3c8b87f0a66293a9d69e65ed2a127180c (diff) | |
download | mariadb-git-d912a758b02399c28cb30d97496ad5cdab35d214.tar.gz |
Bug#14466617 - INVALID WRITES AND/OR CRASH WITH USER
VARIABLES
Analysis:
-------------
After executing the query, new value of the user defined
variables are set in the function "select_dumpvar::send_data".
"select_dumpvar::send_data" first calls function
"Item_func_set_user_var::save_item_result()". This function
checks the nullness of the Item_field passed as parameter
to it and saves it. The nullness of item is stored with
arg[0]'s null_value flag. Then "select_dumpvar::send_data" calls
"Item_func_set_user_var::update()" which notices null
result that was saved and calls "Item_func_set_user_var::
update_hash". But here null_value is not set and args[0]
is different from that given to function "Item_func_set_user_var::
set_item_result()". This causes "Item_func_set_user_var::
update_hash" function to believe that its getting non-null value.
"user_var_entry::length" set to 0 and hence "user_var_entry::value"
is made to point to extra_area allocated in "user_var_entry".
And "Item_func_set_user_var::update_hash" tries to write
at memory beyond extra_area for result type DECIMAL. Because of
this invalid write issue is reported by Valgrind.
Before this bug was introduced, we avoided this problem by
creating "Item_func_set_user_var" object with the same
Item_field as arg[0] and as parameter to
Item_func_set_user_var::save_item_result(). But now
they are refering to different args[0]. Because of this
null_value flag set in parameter Item_field in function
"Item_func_set_user_var::save_item_result()" is not
reflected in "Item_func_set_user_var" object.
Fix:
------------
This issue is reported on versions 5.5.24. Issue does not exists
in 5.5.23, 5.1, 5.6 and trunk.
This issue was introduced by
revid:georgi.kodinov@oracle.com-20120309130449-82e3bs5v3et1x0ef (fix for
bug #12408412), which was pushed into 5.5 and later releases. This patch
has later been reversed in 5.6 and trunk by
revid:norvald.ryeng@oracle.com-20121010135242-xj34gg73h04hrmyh (fix for
bug #14664077). Backported this patch in 5.5 also to fix this issue.
sql/item_func.cc:
here unsigned value is converted to signed value.
sql/item_func.h:
last_insert_id() gives an auto_incremented value which can be
positive only,so defined it as a unsigned longlong sets the
unsigned_flag to 1.
Diffstat (limited to 'sql/item_func.cc')
-rw-r--r-- | sql/item_func.cc | 29 |
1 files changed, 21 insertions, 8 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc index be8ee84712a..39d19fab421 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4222,13 +4222,18 @@ bool Item_func_set_user_var::set_entry(THD *thd, bool create_if_not_exists) 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 - is different from query_id). - */ + end: - entry->update_query_id= thd->query_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 + is different from query_id). + + If this object has delayed setting of non-constness, we delay this + until Item_func_set-user_var::save_item_result() + */ + if (!delayed_non_constness) + entry->update_query_id= thd->query_id; return FALSE; } @@ -4616,6 +4621,13 @@ void Item_func_set_user_var::save_item_result(Item *item) DBUG_ASSERT(0); break; } + /* + Set the ID of the query that last updated this variable. This is + usually set by Item_func_set_user_var::set_entry(), but if this + item has delayed setting of non-constness, we must do it now. + */ + if (delayed_non_constness) + entry->update_query_id= current_thd->query_id; DBUG_VOID_RETURN; } @@ -5022,7 +5034,8 @@ get_var_with_binlog(THD *thd, enum_sql_command sql_command, thd->lex= &lex_tmp; lex_start(thd); tmp_var_list.push_back(new set_var_user(new Item_func_set_user_var(name, - new Item_null()))); + new Item_null(), + false))); /* Create the variable */ if (sql_set_variables(thd, &tmp_var_list)) { @@ -5185,7 +5198,7 @@ bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const bool Item_func_get_user_var::set_value(THD *thd, sp_rcontext * /*ctx*/, Item **it) { - Item_func_set_user_var *suv= new Item_func_set_user_var(get_name(), *it); + Item_func_set_user_var *suv= new Item_func_set_user_var(get_name(), *it, false); /* Item_func_set_user_var is not fixed after construction, call fix_fields(). |