Commit 5c5a116b authored by Alexander Barkov's avatar Alexander Barkov

MDEV-16614 signal 7 after calling stored procedure, that uses regexp

The problem happened in the derived condition pushdown code:
- When Item_func_regex::build_clone() was called, it created a copy of
  the original Item_func_regex, and this copy got registered in free_list.
  Class specific additional dynamic members (such as "re") made
  a shallow copy, rather than a deep copy, in the cloned Item_func_regex.
  As a result, the Regexp_processor_pcre::m_pcre of the cloned Item_func_regex
  and of the original Item_func_regex pointed to the same compiled regular
  expression.
- On cleanup_items(), both original and cloned copies of Item_func_regex
  called re.cleanup(), which called pcre_free(m_pcre). So the same compiled
  regular expression was freed two times, which was noticed by ASAN.

The same problem was repeatable for Item_func_regexp_instr.

A similar problem happened for Item_func_sp, for the sp_result_field member.
Both original and cloned copies of Item_func_sp pointed the same Field instance
and both deleted it on cleanup().

A possible solution would be to fix build_clone() to create deep
(instead of shallow) copies for the dynamic members of the affected classes
(Item_func_regex, Item_func_regexp_instr, Item_func sp).
However, this would be too complex.

As agreed with Galina and Igor, this patch disallows using using these
affected classes in derived condition pushdown by overriding get_clone()
to return NULL.
parent 3c141e31
......@@ -9827,3 +9827,50 @@ WHERE (SELECT BIT_COUNT(t2.i1)
FROM (t2 JOIN t3)) IS NULL;
ERROR 21000: Subquery returns more than 1 row
DROP TABLE t1, t2, t3;
#
# MDEV-16614 signal 7 after calling stored procedure, that uses regexp
#
CREATE PROCEDURE p1(m1 varchar(5), m2 varchar(5))
BEGIN
SELECT a FROM
(SELECT "aa" a) t
JOIN (SELECT "aa" b) t1 on t.a=t1.b
WHERE t.a regexp m1 and t1.b regexp m2
GROUP BY a;
END$$
CALL p1('a','a');
a
aa
DROP PROCEDURE p1;
CREATE PROCEDURE p1(m1 varchar(5))
BEGIN
SELECT a FROM (SELECT "aa" a) t WHERE t.a regexp m1;
END$$
CALL p1('a');
a
aa
DROP PROCEDURE p1;
SELECT a FROM (SELECT "aa" a) t WHERE REGEXP_INSTR(t.a, (SELECT MAX('aa') FROM DUAL LIMIT 1));
a
aa
CREATE OR REPLACE FUNCTION f1(a VARCHAR(10), b VARCHAR(10)) RETURNS INT
BEGIN
RETURN 1;
END;$$
CREATE OR REPLACE PROCEDURE p1(m1 varchar(5))
BEGIN
SELECT a FROM (SELECT "aa" a) t WHERE f1(t.a, m1);
END$$
CALL p1('a');
a
aa
DROP PROCEDURE p1;
DROP FUNCTION f1;
CREATE OR REPLACE FUNCTION f1(a VARCHAR(10), b VARCHAR(10)) RETURNS INT
BEGIN
RETURN 1;
END;$$
SELECT a FROM (SELECT "aa" a) t WHERE f1(t.a, (SELECT MAX('aa') FROM DUAL LIMIT 1));
a
aa
DROP FUNCTION f1;
......@@ -1865,3 +1865,58 @@ WHERE (SELECT BIT_COUNT(t2.i1)
FROM (t2 JOIN t3)) IS NULL;
DROP TABLE t1, t2, t3;
--echo #
--echo # MDEV-16614 signal 7 after calling stored procedure, that uses regexp
--echo #
DELIMITER $$;
CREATE PROCEDURE p1(m1 varchar(5), m2 varchar(5))
BEGIN
SELECT a FROM
(SELECT "aa" a) t
JOIN (SELECT "aa" b) t1 on t.a=t1.b
WHERE t.a regexp m1 and t1.b regexp m2
GROUP BY a;
END$$
DELIMITER ;$$
CALL p1('a','a');
DROP PROCEDURE p1;
DELIMITER $$;
CREATE PROCEDURE p1(m1 varchar(5))
BEGIN
SELECT a FROM (SELECT "aa" a) t WHERE t.a regexp m1;
END$$
DELIMITER ;$$
CALL p1('a');
DROP PROCEDURE p1;
SELECT a FROM (SELECT "aa" a) t WHERE REGEXP_INSTR(t.a, (SELECT MAX('aa') FROM DUAL LIMIT 1));
DELIMITER $$;
CREATE OR REPLACE FUNCTION f1(a VARCHAR(10), b VARCHAR(10)) RETURNS INT
BEGIN
RETURN 1;
END;$$
CREATE OR REPLACE PROCEDURE p1(m1 varchar(5))
BEGIN
SELECT a FROM (SELECT "aa" a) t WHERE f1(t.a, m1);
END$$
DELIMITER ;$$
CALL p1('a');
DROP PROCEDURE p1;
DROP FUNCTION f1;
DELIMITER $$;
CREATE OR REPLACE FUNCTION f1(a VARCHAR(10), b VARCHAR(10)) RETURNS INT
BEGIN
RETURN 1;
END;$$
DELIMITER ;$$
SELECT a FROM (SELECT "aa" a) t WHERE f1(t.a, (SELECT MAX('aa') FROM DUAL LIMIT 1));
DROP FUNCTION f1;
......@@ -2117,16 +2117,7 @@ class Item_func_regex :public Item_bool_func
bool fix_length_and_dec();
const char *func_name() const { return "regexp"; }
enum precedence precedence() const { return CMP_PRECEDENCE; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_regex>(thd, mem_root, this); }
Item *build_clone(THD *thd, MEM_ROOT *mem_root)
{
Item_func_regex *clone= (Item_func_regex*) Item_bool_func::build_clone(thd, mem_root);
if (clone)
clone->re.reset();
return clone;
}
Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; }
void print(String *str, enum_query_type query_type)
{
print_op(str, query_type);
......@@ -2154,8 +2145,7 @@ class Item_func_regexp_instr :public Item_int_func
bool fix_fields(THD *thd, Item **ref);
bool fix_length_and_dec();
const char *func_name() const { return "regexp_instr"; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_regexp_instr>(thd, mem_root, this); }
Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; }
};
......
......@@ -2439,15 +2439,7 @@ class Item_func_sp :public Item_func
{
return TRUE;
}
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_sp>(thd, mem_root, this); }
Item *build_clone(THD *thd, MEM_ROOT *mem_root)
{
Item_func_sp *clone= (Item_func_sp *) Item_func::build_clone(thd, mem_root);
if (clone)
clone->sp_result_field= NULL;
return clone;
}
Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; }
bool eval_not_null_tables(void *opt_arg)
{
not_null_tables_cache= 0;
......
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