diff options
author | Nikita Malyavin <nikitamalyavin@gmail.com> | 2022-04-13 22:08:06 +0300 |
---|---|---|
committer | Nikita Malyavin <nikitamalyavin@gmail.com> | 2022-04-13 22:21:46 +0300 |
commit | c8cf6c31ced1b5a6698b124a2c4aaaec6d3f85b9 (patch) | |
tree | 999b94a66a879831a138b202749d07f3a8ed8d07 | |
parent | 767d8d8335f9d45efb86c77a9efa0b42aff1eb27 (diff) | |
download | mariadb-git-bb-10.2-nikita.tar.gz |
MDEV-26281 ASAN use-after-poison when complex conversion involved in blobbb-10.2-nikita
The problem existed for long. Item_func_in::create_array allocates `array`
on mem_root but releases it with C++ `delete` in Item_func_in::cleanup().
Allocating on a mem root is incorrect in a case of Item, since it controls
its memory by an independent mechanism, and its lifetime differs from
mem_roots (thd, stmt, table).
It was also incorrect to allocate in_vector::base on mem_root by the same
reasons (also done in in_row).
So far, thd argument has been completely removed from constructors of the
hierarchy, and RAII memory management is favored.
-rw-r--r-- | mysql-test/suite/gcol/r/gcol_bugfixes.result | 59 | ||||
-rw-r--r-- | mysql-test/suite/gcol/t/gcol_bugfixes.test | 57 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 33 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 28 |
4 files changed, 148 insertions, 29 deletions
diff --git a/mysql-test/suite/gcol/r/gcol_bugfixes.result b/mysql-test/suite/gcol/r/gcol_bugfixes.result index 4bc424d1b1e..7dac0876558 100644 --- a/mysql-test/suite/gcol/r/gcol_bugfixes.result +++ b/mysql-test/suite/gcol/r/gcol_bugfixes.result @@ -743,3 +743,62 @@ SELECT id, ts, vc INTO OUTFILE 'load_t1' FROM t1; LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id, ts, vc); INSERT IGNORE INTO t1 (id) VALUES (2); DROP TABLE t1; +# MDEV-26281 ASAN use-after-poison when complex conversion involved +# in blob +CREATE TEMPORARY TABLE v0 ( +v2 TINYBLOB AS (CURRENT_USER IS NULL IS UNKNOWN) VIRTUAL, +v1 TINYINT ZEROFILL , +MEDIUM NCHAR BINARY GENERATED ALWAYS AS ( CONVERT( +v1 IN (FALSE, CURRENT_USER() IS NULL IS NULL, 34), +BINARY (97015438.000000)) IS NOT UNKNOWN ) +); +ALTER TABLE v0 +ADD COLUMN v0 MEDIUMINT ZEROFILL KEY UNIQUE COMMENT 'x'; +INSERT IGNORE INTO v0 VALUES +(CONVERT('x' LIKE v1 IS UNKNOWN, TIME), 'x', +v2 IN (v2 SOUNDS LIKE v1 IS FALSE) IS UNKNOWN, +CONVERT('x' REGEXP 'x' IS NOT FALSE USING BINARY) IN +(TRUE LIKE v1 IS NOT UNKNOWN)); +Warnings: +Warning 1366 Incorrect integer value: 'x' for column `test`.`v0`.`v1` at row 1 +Warning 1301 Result of cast_as_binary() was larger than max_allowed_packet (16777216) - truncated +SELECT * FROM v0; +v2 v1 MEDIUM v0 +0 000 1 00000001 +DROP TABLE v0; +CREATE TABLE t1 ( +v2 BLOB AS ('a' IS NULL), +a1 INT, +a CHAR(1) AS (CAST(a1 IN (0, current_user() IS NULL) AS CHAR(16777216))) +); +INSERT IGNORE INTO t1 VALUES ('x', 'x', v2); +Warnings: +Warning 1906 The value specified for generated column 'v2' in table 't1' has been ignored +Warning 1366 Incorrect integer value: 'x' for column `test`.`t1`.`a1` at row 1 +Warning 1906 The value specified for generated column 'a' in table 't1' has been ignored +SELECT * FROM t1; +v2 a1 a +0 0 1 +DROP TABLE t1; +CREATE TABLE `t1` +( +`v2` TINYBLOB GENERATED ALWAYS AS (current_user() IS NULL IS NULL) VIRTUAL, +`v1` TINYINT(3) UNSIGNED ZEROFILL DEFAULT NULL, +`MEDIUM` char(1) CHARACTER SET utf8 COLLATE utf8_bin GENERATED ALWAYS AS (cast( +`v1` in (0, current_user() IS NULL IS NULL, +34) AS CHAR(16777216) CHARSET binary) IS NOT NULL) VIRTUAL, +`t1` MEDIUMINT(8) UNSIGNED ZEROFILL NOT NULL COMMENT 'x', +PRIMARY KEY (`t1`) +); +INSERT IGNORE INTO t1 VALUES +(CONVERT('x' LIKE v1 IS UNKNOWN, TIME), 'x', +v2 IN (v2 SOUNDS LIKE v1 IS FALSE) IS UNKNOWN, +1); +Warnings: +Warning 1906 The value specified for generated column 'v2' in table 't1' has been ignored +Warning 1366 Incorrect integer value: 'x' for column `test`.`t1`.`v1` at row 1 +Warning 1906 The value specified for generated column 'MEDIUM' in table 't1' has been ignored +SELECT * FROM t1; +v2 v1 MEDIUM t1 +0 000 1 00000001 +DROP TABLE t1; diff --git a/mysql-test/suite/gcol/t/gcol_bugfixes.test b/mysql-test/suite/gcol/t/gcol_bugfixes.test index a1f277199eb..ac709c998a1 100644 --- a/mysql-test/suite/gcol/t/gcol_bugfixes.test +++ b/mysql-test/suite/gcol/t/gcol_bugfixes.test @@ -717,4 +717,61 @@ DROP TABLE t1; --let $datadir= `select @@datadir` --remove_file $datadir/test/load_t1 +--echo # MDEV-26281 ASAN use-after-poison when complex conversion involved +--echo # in blob + +CREATE TEMPORARY TABLE v0 ( + v2 TINYBLOB AS (CURRENT_USER IS NULL IS UNKNOWN) VIRTUAL, + v1 TINYINT ZEROFILL , + MEDIUM NCHAR BINARY GENERATED ALWAYS AS ( CONVERT( + v1 IN (FALSE, CURRENT_USER() IS NULL IS NULL, 34), + BINARY (97015438.000000)) IS NOT UNKNOWN ) +); + +ALTER TABLE v0 + ADD COLUMN v0 MEDIUMINT ZEROFILL KEY UNIQUE COMMENT 'x'; + +INSERT IGNORE INTO v0 VALUES + (CONVERT('x' LIKE v1 IS UNKNOWN, TIME), 'x', + v2 IN (v2 SOUNDS LIKE v1 IS FALSE) IS UNKNOWN, + CONVERT('x' REGEXP 'x' IS NOT FALSE USING BINARY) IN + (TRUE LIKE v1 IS NOT UNKNOWN)); + +SELECT * FROM v0; + +DROP TABLE v0; + +CREATE TABLE t1 ( + v2 BLOB AS ('a' IS NULL), + a1 INT, + a CHAR(1) AS (CAST(a1 IN (0, current_user() IS NULL) AS CHAR(16777216))) +); + +INSERT IGNORE INTO t1 VALUES ('x', 'x', v2); + +SELECT * FROM t1; + +DROP TABLE t1; + + + +CREATE TABLE `t1` +( + `v2` TINYBLOB GENERATED ALWAYS AS (current_user() IS NULL IS NULL) VIRTUAL, + `v1` TINYINT(3) UNSIGNED ZEROFILL DEFAULT NULL, + `MEDIUM` char(1) CHARACTER SET utf8 COLLATE utf8_bin GENERATED ALWAYS AS (cast( + `v1` in (0, current_user() IS NULL IS NULL, + 34) AS CHAR(16777216) CHARSET binary) IS NOT NULL) VIRTUAL, + `t1` MEDIUMINT(8) UNSIGNED ZEROFILL NOT NULL COMMENT 'x', + PRIMARY KEY (`t1`) +); + +INSERT IGNORE INTO t1 VALUES + (CONVERT('x' LIKE v1 IS UNKNOWN, TIME), 'x', + v2 IN (v2 SOUNDS LIKE v1 IS FALSE) IS UNKNOWN, + 1); +SELECT * FROM t1; + +DROP TABLE t1; + diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 3a76982d80e..02af28881bd 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3659,9 +3659,9 @@ bool in_vector::find(Item *item) return ((*compare)(collation, base+start*size, result) == 0); } -in_string::in_string(THD *thd, uint elements, qsort2_cmp cmp_func, +in_string::in_string(uint elements, qsort2_cmp cmp_func, CHARSET_INFO *cs) - :in_vector(thd, elements, sizeof(String), cmp_func, cs), + :in_vector(elements, sizeof(String), cmp_func, cs), tmp(buff, sizeof(buff), &my_charset_bin) {} @@ -3709,9 +3709,9 @@ Item *in_string::create_item(THD *thd) } -in_row::in_row(THD *thd, uint elements, Item * item) +in_row::in_row(uint elements, Item * item) { - base= (char*) new (thd->mem_root) cmp_item_row[count= elements]; + base= (char*) new cmp_item_row[count= elements]; size= sizeof(cmp_item_row); compare= (qsort2_cmp) cmp_row; /* @@ -3744,9 +3744,8 @@ void in_row::set(uint pos, Item *item) DBUG_VOID_RETURN; } -in_longlong::in_longlong(THD *thd, uint elements) - :in_vector(thd, elements, sizeof(packed_longlong), - (qsort2_cmp) cmp_longlong, 0) +in_longlong::in_longlong(uint elements) + :in_vector(elements, sizeof(packed_longlong), (qsort2_cmp) cmp_longlong, 0) {} void in_longlong::set(uint pos,Item *item) @@ -3800,8 +3799,8 @@ Item *in_datetime::create_item(THD *thd) } -in_double::in_double(THD *thd, uint elements) - :in_vector(thd, elements, sizeof(double), (qsort2_cmp) cmp_double, 0) +in_double::in_double(uint elements) + :in_vector(elements, sizeof(double), (qsort2_cmp) cmp_double, 0) {} void in_double::set(uint pos,Item *item) @@ -3823,8 +3822,8 @@ Item *in_double::create_item(THD *thd) } -in_decimal::in_decimal(THD *thd, uint elements) - :in_vector(thd, elements, sizeof(my_decimal), (qsort2_cmp) cmp_decimal, 0) +in_decimal::in_decimal(uint elements) + :in_vector(elements, sizeof(my_decimal), (qsort2_cmp) cmp_decimal, 0) {} @@ -4183,15 +4182,15 @@ bool Item_func_in::create_array(THD *thd) switch (m_compare_type) { case STRING_RESULT: - array=new (thd->mem_root) in_string(thd, arg_count - 1, + array= new in_string(arg_count - 1, (qsort2_cmp) srtcmp_in, cmp_collation.collation); break; case INT_RESULT: - array= new (thd->mem_root) in_longlong(thd, arg_count - 1); + array= new in_longlong(arg_count - 1); break; case REAL_RESULT: - array= new (thd->mem_root) in_double(thd, arg_count - 1); + array= new in_double(arg_count - 1); break; case ROW_RESULT: /* @@ -4202,11 +4201,11 @@ bool Item_func_in::create_array(THD *thd) ((in_row*)array)->tmp.store_value(args[0]); break; case DECIMAL_RESULT: - array= new (thd->mem_root) in_decimal(thd, arg_count - 1); + array= new in_decimal(arg_count - 1); break; case TIME_RESULT: date_arg= find_date_time_item(thd, args, arg_count, 0, true); - array= new (thd->mem_root) in_datetime(thd, date_arg, arg_count - 1); + array= new in_datetime(date_arg, arg_count - 1); break; } if (!array || thd->is_fatal_error) // OOM @@ -4303,7 +4302,7 @@ bool Item_func_in::fix_length_and_dec() if (bisection_possible) { - array= new (thd->mem_root) in_row(thd, arg_count-1, 0); + array= new (thd->mem_root) in_row(arg_count-1, 0); if (!array) return TRUE; cmp= &((in_row*)array)->tmp; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 26469d88929..84bb5479273 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1170,7 +1170,7 @@ public: /* A vector of values of some type */ -class in_vector :public Sql_alloc +class in_vector { public: char *base; @@ -1179,13 +1179,17 @@ public: CHARSET_INFO *collation; uint count; uint used_count; - in_vector() {} - in_vector(THD *thd, uint elements, uint element_length, qsort2_cmp cmp_func, + in_vector(): base(NULL) {} + in_vector(uint elements, uint element_length, qsort2_cmp cmp_func, CHARSET_INFO *cmp_coll) - :base((char*) thd_calloc(thd, elements * element_length)), + :base((char*)calloc(elements, element_length)), size(element_length), compare(cmp_func), collation(cmp_coll), count(elements), used_count(elements) {} - virtual ~in_vector() {} + virtual ~in_vector() + { + free(base); + base= NULL; + } virtual void set(uint pos,Item *item)=0; virtual uchar *get_value(Item *item)=0; void sort() @@ -1239,7 +1243,7 @@ class in_string :public in_vector } }; public: - in_string(THD *thd, uint elements, qsort2_cmp cmp_func, CHARSET_INFO *cs); + in_string(uint elements, qsort2_cmp cmp_func, CHARSET_INFO *cs); ~in_string(); void set(uint pos,Item *item); uchar *get_value(Item *item); @@ -1267,7 +1271,7 @@ protected: longlong unsigned_flag; // Use longlong, not bool, to preserve alignment } tmp; public: - in_longlong(THD *thd, uint elements); + in_longlong(uint elements); void set(uint pos,Item *item); uchar *get_value(Item *item); Item* create_item(THD *thd); @@ -1292,8 +1296,8 @@ public: /* An item used to issue warnings. */ Item *warn_item; - in_datetime(THD *thd, Item *warn_item_arg, uint elements) - :in_longlong(thd, elements), warn_item(warn_item_arg) {} + in_datetime(Item *warn_item_arg, uint elements) + :in_longlong(elements), warn_item(warn_item_arg) {} void set(uint pos,Item *item); uchar *get_value(Item *item); Item *create_item(THD *thd); @@ -1311,7 +1315,7 @@ class in_double :public in_vector { double tmp; public: - in_double(THD *thd, uint elements); + in_double(uint elements); void set(uint pos,Item *item); uchar *get_value(Item *item); Item *create_item(THD *thd); @@ -1327,7 +1331,7 @@ class in_decimal :public in_vector { my_decimal val; public: - in_decimal(THD *thd, uint elements); + in_decimal(uint elements); void set(uint pos, Item *item); uchar *get_value(Item *item); Item *create_item(THD *thd); @@ -1734,7 +1738,7 @@ class in_row :public in_vector { cmp_item_row tmp; public: - in_row(THD *thd, uint elements, Item *); + in_row(uint elements, Item *); ~in_row(); void set(uint pos,Item *item); uchar *get_value(Item *item); |