summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGleb Shchepa <gleb.shchepa@oracle.com>2010-11-24 23:03:16 +0300
committerGleb Shchepa <gleb.shchepa@oracle.com>2010-11-24 23:03:16 +0300
commitd85c3053625f7bd394e8f7954eb874a7c74ad2ea (patch)
tree54fe1f851f9fabd7047d53d60e1abe84cfa23a9f
parentb6b7fb2bfa36ed7b5ae391218f9259a078366f44 (diff)
downloadmariadb-git-d85c3053625f7bd394e8f7954eb874a7c74ad2ea.tar.gz
backport of bug #54461 from 5.1-security to 5.0-security
> revision-id: gshchepa@mysql.com-20100801181236-uyuq6ewaq43rw780 > parent: alexey.kopytov@sun.com-20100723115254-jjwmhq97b9wl932l > committer: Gleb Shchepa <gshchepa@mysql.com> > branch nick: mysql-5.1-security > timestamp: Sun 2010-08-01 22:12:36 +0400 > 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.test13
-rw-r--r--sql/item_func.cc2
3 files changed, 29 insertions, 1 deletions
diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result
index 9f2fcb06638..f23718466d3 100644
--- a/mysql-test/r/func_misc.result
+++ b/mysql-test/r/func_misc.result
@@ -327,4 +327,19 @@ DROP TABLE t1;
select NAME_CONST('_id',1234) as id;
id
1234
+#
+# 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 5.0 tests
diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test
index 01c508c9b58..89359fab0ca 100644
--- a/mysql-test/t/func_misc.test
+++ b/mysql-test/t/func_misc.test
@@ -450,5 +450,16 @@ DROP TABLE t1;
#
select NAME_CONST('_id',1234) as id;
---echo End of 5.0 tests
+--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 5.0 tests
diff --git a/sql/item_func.cc b/sql/item_func.cc
index cb0d6bdbe5f..8af7db7fa1a 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2250,6 +2250,8 @@ void Item_func_min_max::fix_length_and_dec()
else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT))
max_length= my_decimal_precision_to_length(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);
}