Commit 405bd2af authored by Gleb Shchepa's avatar Gleb Shchepa

Bug #44768: SIGFPE crash when selecting rand from a view containing null

The RAND(N) function where the N is a field of "constant" table
(table of single row) failed with a SIGFPE.

Evaluation of RAND(N) rely on constant status of its argument.
Current server "seeded" random value for each constant argument
only once, in the Item_func_rand::fix_fields method.
Then the server skipped a call to seed_random() in the
Item_func_rand::val_real method for such constant arguments.

However, non-constant state of an argument may be changed
after the call to fix_fields, if an argument is a field of
"constant" table. Thus, pre-initialization of random value
in the fix_fields method is too early.


Initialization of random value by seed_random() has been
removed from Item_func_rand::fix_fields method.
The Item_func_rand::val_real method has been modified to
call seed_random() on the first evaluation of this method
if an argument is a function.


mysql-test/r/func_math.result:
  Added test case for bug #44768.
mysql-test/t/func_math.test:
  Added test case for bug #44768.
sql/item_func.cc:
  Bug #44768: SIGFPE crash when selecting rand from a view containing null
  
  1. Initialization of random value by seed_random() has been
     removed from Item_func_rand::fix_fields method.
  2. The Item_func_rand::val_real method has been modified to
     call seed_random() on the first evaluation of this method
     if an argument is a function.
sql/item_func.h:
  Bug #44768: SIGFPE crash when selecting rand from a view containing null
  
  1. The Item_func_rand::first_eval has been added to trace
     the first evaluation of the val_real method.
  2. The Item_func_rand::cleanup method has been added to
     cleanup the first_eval flag.
parent baeac876
...@@ -456,4 +456,23 @@ NULL ...@@ -456,4 +456,23 @@ NULL
SELECT POW(10, 309); SELECT POW(10, 309);
POW(10, 309) POW(10, 309)
NULL NULL
#
# Bug #44768: SIGFPE crash when selecting rand from a view
# containing null
#
CREATE OR REPLACE VIEW v1 AS SELECT NULL AS a;
SELECT RAND(a) FROM v1;
RAND(a)
0.155220427694936
DROP VIEW v1;
SELECT RAND(a) FROM (SELECT NULL AS a) b;
RAND(a)
0.155220427694936
CREATE TABLE t1 (i INT);
INSERT INTO t1 VALUES (NULL);
SELECT RAND(i) FROM t1;
RAND(i)
0.155220427694936
DROP TABLE t1;
#
End of 5.1 tests End of 5.1 tests
...@@ -282,4 +282,22 @@ SELECT 1e300 / 1e-300; ...@@ -282,4 +282,22 @@ SELECT 1e300 / 1e-300;
SELECT EXP(750); SELECT EXP(750);
SELECT POW(10, 309); SELECT POW(10, 309);
--echo #
--echo # Bug #44768: SIGFPE crash when selecting rand from a view
--echo # containing null
--echo #
CREATE OR REPLACE VIEW v1 AS SELECT NULL AS a;
SELECT RAND(a) FROM v1;
DROP VIEW v1;
SELECT RAND(a) FROM (SELECT NULL AS a) b;
CREATE TABLE t1 (i INT);
INSERT INTO t1 VALUES (NULL);
SELECT RAND(i) FROM t1;
DROP TABLE t1;
--echo #
--echo End of 5.1 tests --echo End of 5.1 tests
...@@ -2143,9 +2143,6 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref) ...@@ -2143,9 +2143,6 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref)
if (!rand && !(rand= (struct rand_struct*) if (!rand && !(rand= (struct rand_struct*)
thd->stmt_arena->alloc(sizeof(*rand)))) thd->stmt_arena->alloc(sizeof(*rand))))
return TRUE; return TRUE;
if (args[0]->const_item())
seed_random (args[0]);
} }
else else
{ {
...@@ -2175,8 +2172,21 @@ void Item_func_rand::update_used_tables() ...@@ -2175,8 +2172,21 @@ void Item_func_rand::update_used_tables()
double Item_func_rand::val_real() double Item_func_rand::val_real()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
if (arg_count && !args[0]->const_item()) if (arg_count)
seed_random (args[0]); {
if (!args[0]->const_item())
seed_random(args[0]);
else if (first_eval)
{
/*
Constantness of args[0] may be set during JOIN::optimize(), if arg[0]
is a field item of "constant" table. Thus, we have to evaluate
seed_random() for constant arg there but not at the fix_fields method.
*/
first_eval= FALSE;
seed_random(args[0]);
}
}
return my_rnd(rand); return my_rnd(rand);
} }
......
...@@ -696,14 +696,16 @@ class Item_func_round :public Item_func_num1 ...@@ -696,14 +696,16 @@ class Item_func_round :public Item_func_num1
class Item_func_rand :public Item_real_func class Item_func_rand :public Item_real_func
{ {
struct rand_struct *rand; struct rand_struct *rand;
bool first_eval; // TRUE if val_real() is called 1st time
public: public:
Item_func_rand(Item *a) :Item_real_func(a), rand(0) {} Item_func_rand(Item *a) :Item_real_func(a), rand(0), first_eval(TRUE) {}
Item_func_rand() :Item_real_func() {} Item_func_rand() :Item_real_func() {}
double val_real(); double val_real();
const char *func_name() const { return "rand"; } const char *func_name() const { return "rand"; }
bool const_item() const { return 0; } bool const_item() const { return 0; }
void update_used_tables(); void update_used_tables();
bool fix_fields(THD *thd, Item **ref); bool fix_fields(THD *thd, Item **ref);
void cleanup() { first_eval= TRUE; Item_real_func::cleanup(); }
private: private:
void seed_random (Item * val); void seed_random (Item * val);
}; };
......
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