summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Malyavin <nikitamalyavin@gmail.com>2022-04-13 22:08:06 +0300
committerNikita Malyavin <nikitamalyavin@gmail.com>2022-04-13 22:21:46 +0300
commitc8cf6c31ced1b5a6698b124a2c4aaaec6d3f85b9 (patch)
tree999b94a66a879831a138b202749d07f3a8ed8d07
parent767d8d8335f9d45efb86c77a9efa0b42aff1eb27 (diff)
downloadmariadb-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.result59
-rw-r--r--mysql-test/suite/gcol/t/gcol_bugfixes.test57
-rw-r--r--sql/item_cmpfunc.cc33
-rw-r--r--sql/item_cmpfunc.h28
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);