Commit c4b29069 authored by Sergey Glukhov's avatar Sergey Glukhov

Bug#58030 crash in Item_func_geometry_from_text::val_str

Item_sum_max/Item_sum_min incorrectly set null_value flag and
attempt to get result in parent functions leads to crash.
This happens due to double evaluation of the function argumet.
First evaluation happens in the comparator and second one
happens in Item_cache::cache_value().
The fix is to introduce new Item_cache object which
holds result of the argument and use this cached value
as an argument of the comparator.
parent 16ca2deb
...@@ -1724,4 +1724,16 @@ m ...@@ -1724,4 +1724,16 @@ m
1 1
DROP TABLE t1; DROP TABLE t1;
# #
# Bug#58030 crash in Item_func_geometry_from_text::val_str
#
SELECT MAX(TIMESTAMP(RAND(0)));
SELECT MIN(TIMESTAMP(RAND(0)));
#
# Bug#58177 crash and valgrind warnings in decimal and protocol sending functions...
#
SELECT MIN(GET_LOCK('aaaaaaaaaaaaaaaaa',0) / '0b1111111111111111111111111111111111111111111111111111111111111111111111111' ^ (RAND()));
SELECT MIN(GET_LOCK('aaaaaaaaaaaaaaaaa',0) / '0b1111111111111111111111111111111111111111111111111111111111111111111111111' ^ (RAND()));
SELECT MIN(GET_LOCK('aaaaaaaaaaaaaaaaa',0) / '0b1111111111111111111111111111111111111111111111111111111111111111111111111' ^ (RAND()));
SELECT MIN(GET_LOCK('aaaaaaaaaaaaaaaaa',0) / '0b1111111111111111111111111111111111111111111111111111111111111111111111111' ^ (RAND()));
#
End of 5.1 tests End of 5.1 tests
...@@ -1096,6 +1096,26 @@ SELECT MAX((SELECT 1 FROM t1 ORDER BY @var LIMIT 1)) m FROM t1 t2, t1 ...@@ -1096,6 +1096,26 @@ SELECT MAX((SELECT 1 FROM t1 ORDER BY @var LIMIT 1)) m FROM t1 t2, t1
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # Bug#58030 crash in Item_func_geometry_from_text::val_str
--echo #
--disable_result_log
SELECT MAX(TIMESTAMP(RAND(0)));
SELECT MIN(TIMESTAMP(RAND(0)));
--echo #
--echo # Bug#58177 crash and valgrind warnings in decimal and protocol sending functions...
--echo #
SELECT MIN(GET_LOCK('aaaaaaaaaaaaaaaaa',0) / '0b1111111111111111111111111111111111111111111111111111111111111111111111111' ^ (RAND()));
SELECT MIN(GET_LOCK('aaaaaaaaaaaaaaaaa',0) / '0b1111111111111111111111111111111111111111111111111111111111111111111111111' ^ (RAND()));
SELECT MIN(GET_LOCK('aaaaaaaaaaaaaaaaa',0) / '0b1111111111111111111111111111111111111111111111111111111111111111111111111' ^ (RAND()));
SELECT MIN(GET_LOCK('aaaaaaaaaaaaaaaaa',0) / '0b1111111111111111111111111111111111111111111111111111111111111111111111111' ^ (RAND()));
--enable_result_log
--echo # --echo #
--echo End of 5.1 tests --echo End of 5.1 tests
...@@ -5572,6 +5572,10 @@ bool Item::send(Protocol *protocol, String *buffer) ...@@ -5572,6 +5572,10 @@ bool Item::send(Protocol *protocol, String *buffer)
String *res; String *res;
if ((res=val_str(buffer))) if ((res=val_str(buffer)))
result= protocol->store(res->ptr(),res->length(),res->charset()); result= protocol->store(res->ptr(),res->length(),res->charset());
else
{
DBUG_ASSERT(null_value);
}
break; break;
} }
case MYSQL_TYPE_TINY: case MYSQL_TYPE_TINY:
......
...@@ -666,8 +666,10 @@ void Item_sum_hybrid::setup_hybrid(Item *item, Item *value_arg) ...@@ -666,8 +666,10 @@ void Item_sum_hybrid::setup_hybrid(Item *item, Item *value_arg)
value= Item_cache::get_cache(item); value= Item_cache::get_cache(item);
value->setup(item); value->setup(item);
value->store(value_arg); value->store(value_arg);
arg_cache= Item_cache::get_cache(item);
arg_cache->setup(item);
cmp= new Arg_comparator(); cmp= new Arg_comparator();
cmp->set_cmp_func(this, args, (Item**)&value, FALSE); cmp->set_cmp_func(this, (Item**)&arg_cache, (Item**)&value, FALSE);
collation.set(item->collation); collation.set(item->collation);
} }
...@@ -1639,11 +1641,11 @@ Item *Item_sum_min::copy_or_same(THD* thd) ...@@ -1639,11 +1641,11 @@ Item *Item_sum_min::copy_or_same(THD* thd)
bool Item_sum_min::add() bool Item_sum_min::add()
{ {
/* args[0] < value */ /* args[0] < value */
int res= cmp->compare(); arg_cache->cache_value();
if (!args[0]->null_value && if (!arg_cache->null_value &&
(null_value || res < 0)) (null_value || cmp->compare() < 0))
{ {
value->store(args[0]); value->store(arg_cache);
value->cache_value(); value->cache_value();
null_value= 0; null_value= 0;
} }
...@@ -1662,11 +1664,11 @@ Item *Item_sum_max::copy_or_same(THD* thd) ...@@ -1662,11 +1664,11 @@ Item *Item_sum_max::copy_or_same(THD* thd)
bool Item_sum_max::add() bool Item_sum_max::add()
{ {
/* args[0] > value */ /* args[0] > value */
int res= cmp->compare(); arg_cache->cache_value();
if (!args[0]->null_value && if (!arg_cache->null_value &&
(null_value || res > 0)) (null_value || cmp->compare() > 0))
{ {
value->store(args[0]); value->store(arg_cache);
value->cache_value(); value->cache_value();
null_value= 0; null_value= 0;
} }
......
...@@ -823,7 +823,7 @@ class Item_cache; ...@@ -823,7 +823,7 @@ class Item_cache;
class Item_sum_hybrid :public Item_sum class Item_sum_hybrid :public Item_sum
{ {
protected: protected:
Item_cache *value; Item_cache *value, *arg_cache;
Arg_comparator *cmp; Arg_comparator *cmp;
Item_result hybrid_type; Item_result hybrid_type;
enum_field_types hybrid_field_type; enum_field_types hybrid_field_type;
...@@ -832,14 +832,14 @@ protected: ...@@ -832,14 +832,14 @@ protected:
public: public:
Item_sum_hybrid(Item *item_par,int sign) Item_sum_hybrid(Item *item_par,int sign)
:Item_sum(item_par), value(0), cmp(0), :Item_sum(item_par), value(0), arg_cache(0), cmp(0),
hybrid_type(INT_RESULT), hybrid_field_type(MYSQL_TYPE_LONGLONG), hybrid_type(INT_RESULT), hybrid_field_type(MYSQL_TYPE_LONGLONG),
cmp_sign(sign), was_values(TRUE) cmp_sign(sign), was_values(TRUE)
{ collation.set(&my_charset_bin); } { collation.set(&my_charset_bin); }
Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) Item_sum_hybrid(THD *thd, Item_sum_hybrid *item)
:Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type), :Item_sum(thd, item), value(item->value), arg_cache(0),
hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign), hybrid_type(item->hybrid_type), hybrid_field_type(item->hybrid_field_type),
was_values(item->was_values) cmp_sign(item->cmp_sign), was_values(item->was_values)
{ } { }
bool fix_fields(THD *, Item **); bool fix_fields(THD *, Item **);
void setup_hybrid(Item *item, Item *value_arg); void setup_hybrid(Item *item, Item *value_arg);
......
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