summaryrefslogtreecommitdiff
path: root/sql/item_func.cc
diff options
context:
space:
mode:
authorPraveenkumar Hulakund <praveenkumar.hulakund@oracle.com>2012-11-07 19:08:33 +0530
committerPraveenkumar Hulakund <praveenkumar.hulakund@oracle.com>2012-11-07 19:08:33 +0530
commitd912a758b02399c28cb30d97496ad5cdab35d214 (patch)
tree81c1dddbb0ffde40a0473341f3c2a1f8b07d62ac /sql/item_func.cc
parentf5fbcfe3c8b87f0a66293a9d69e65ed2a127180c (diff)
downloadmariadb-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.cc29
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().