summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGleb Shchepa <gshchepa@mysql.com>2010-08-01 22:12:36 +0400
committerGleb Shchepa <gshchepa@mysql.com>2010-08-01 22:12:36 +0400
commit38165ce4a3fdd0d539fa5b0972d105af31a0d134 (patch)
treecc51b601f1e44402353a460d535aafeae348477b
parentbb3fbba1af97d95ec60f604e10796b9cff9b432d (diff)
downloadmariadb-git-38165ce4a3fdd0d539fa5b0972d105af31a0d134.tar.gz
Bug #54461: crash with longblob and union or update with subquery
Queries may crash, if 1) the GREATEST or the LEAST function has a mixed list of numeric and LONGBLOB arguments and 2) the result of such a function goes through an intermediate temporary table. An Item that references a LONGBLOB field has max_length of UINT_MAX32 == (2^32 - 1). The current implementation of GREATEST/LEAST returns REAL result for a mixed list of numeric and string arguments (that contradicts with the current documentation, this contradiction was discussed and it was decided to update the documentation). The max_length of such a function call was calculated as a maximum of argument max_length values (i.e. UINT_MAX32). That max_length value of UINT_MAX32 was used as a length for the intermediate temporary table Field_double to hold GREATEST/LEAST function result. The Field_double::val_str() method call on that field allocates a String value. Since an allocation of String reserves an additional byte for a zero-termination, the size of String buffer was set to (UINT_MAX32 + 1), that caused an integer overflow: actually, an empty buffer of size 0 was allocated. An initialization of the "first" byte of that zero-size buffer with '\0' caused a crash. The Item_func_min_max::fix_length_and_dec() has been modified to calculate max_length for the REAL result like we do it for arithmetical operators. ****** Bug #54461: crash with longblob and union or update with subquery Queries may crash, if 1) the GREATEST or the LEAST function has a mixed list of numeric and LONGBLOB arguments and 2) the result of such a function goes through an intermediate temporary table. An Item that references a LONGBLOB field has max_length of UINT_MAX32 == (2^32 - 1). The current implementation of GREATEST/LEAST returns REAL result for a mixed list of numeric and string arguments (that contradicts with the current documentation, this contradiction was discussed and it was decided to update the documentation). The max_length of such a function call was calculated as a maximum of argument max_length values (i.e. UINT_MAX32). That max_length value of UINT_MAX32 was used as a length for the intermediate temporary table Field_double to hold GREATEST/LEAST function result. The Field_double::val_str() method call on that field allocates a String value. Since an allocation of String reserves an additional byte for a zero-termination, the size of String buffer was set to (UINT_MAX32 + 1), that caused an integer overflow: actually, an empty buffer of size 0 was allocated. An initialization of the "first" byte of that zero-size buffer with '\0' caused a crash. The Item_func_min_max::fix_length_and_dec() has been modified to calculate max_length for the REAL result like we do it for arithmetical operators.
-rw-r--r--mysql-test/r/func_misc.result15
-rw-r--r--mysql-test/t/func_misc.test12
-rw-r--r--sql/item_func.cc2
3 files changed, 29 insertions, 0 deletions
diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result
index 81dddd0f648..eee56ae7461 100644
--- a/mysql-test/r/func_misc.result
+++ b/mysql-test/r/func_misc.result
@@ -336,4 +336,19 @@ End of 5.0 tests
select connection_id() > 0;
connection_id() > 0
1
+#
+# Bug #54461: crash with longblob and union or update with subquery
+#
+CREATE TABLE t1 (a INT, b LONGBLOB);
+INSERT INTO t1 VALUES (1, '2'), (2, '3'), (3, '2');
+SELECT DISTINCT LEAST(a, (SELECT b FROM t1 LIMIT 1)) FROM t1 UNION SELECT 1;
+LEAST(a, (SELECT b FROM t1 LIMIT 1))
+1
+2
+SELECT DISTINCT GREATEST(a, (SELECT b FROM t1 LIMIT 1)) FROM t1 UNION SELECT 1;
+GREATEST(a, (SELECT b FROM t1 LIMIT 1))
+2
+3
+1
+DROP TABLE t1;
End of tests
diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test
index 6590b43f2dc..c6b5ffd5a3f 100644
--- a/mysql-test/t/func_misc.test
+++ b/mysql-test/t/func_misc.test
@@ -467,4 +467,16 @@ select NAME_CONST('_id',1234) as id;
select connection_id() > 0;
+--echo #
+--echo # Bug #54461: crash with longblob and union or update with subquery
+--echo #
+
+CREATE TABLE t1 (a INT, b LONGBLOB);
+INSERT INTO t1 VALUES (1, '2'), (2, '3'), (3, '2');
+
+SELECT DISTINCT LEAST(a, (SELECT b FROM t1 LIMIT 1)) FROM t1 UNION SELECT 1;
+SELECT DISTINCT GREATEST(a, (SELECT b FROM t1 LIMIT 1)) FROM t1 UNION SELECT 1;
+
+DROP TABLE t1;
+
--echo End of tests
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 1bec4700bff..1b13297c951 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2243,6 +2243,8 @@ void Item_func_min_max::fix_length_and_dec()
max_length= my_decimal_precision_to_length_no_truncation(max_int_part +
decimals, decimals,
unsigned_flag);
+ else if (cmp_type == REAL_RESULT)
+ max_length= float_length(decimals);
cached_field_type= agg_field_type(args, arg_count);
}