3119 Tor Didriksen 2011-05-25
Bug#11765562 58545 EXPORT_SET() CAN BE USED TO MAKE ENTIRE SERVER COMPLETELY UNRESPONSIVE
The function EXPORT_SET(bits,on,off[,separator[,number_of_bits]])
will concatenate (up to) 64*2 -1 strings: on/off and separator.
The total length should not be greater than thd->variables.max_allowed_packet.
@ mysql-test/r/func_str.result
New test case.
@ mysql-test/t/func_str.test
New test case.
@ sql/item_strfunc.cc
In Item_func_export_set::val_str, verify that the size of the end result is within reasonable bounds.
@ unittest/gunit/item-t.cc
New test cases.
@ unittest/gunit/test_utils.h
Add accessor for handle_called.
modified:
mysql-test/r/func_str.result
mysql-test/t/func_str.test
sql/item_strfunc.cc
unittest/gunit/item-t.cc
unittest/gunit/test_utils.h
3118 Anitha Gopi 2011-05-27 [merge]
Automerge : Update local tree
added:
mysql-test/suite/binlog/r/binlog_reset_master.result
mysql-test/suite/binlog/t/binlog_reset_master.test
mysql-test/suite/rpl/t/rpl_typeconv-master.opt
modified:
BUILD/SETUP.sh
cmake/configure.pl
cmake/os/WindowsCache.cmake
include/violite.h
libmysql/errmsg.c
mysql-test/include/subquery.inc
mysql-test/lib/mtr_misc.pl
mysql-test/mysql-test-run.pl
mysql-test/r/func_math.result
mysql-test/r/openssl_1.result
mysql-test/r/subquery_nomat_nosj.result
mysql-test/r/subquery_none.result
mysql-test/suite/innodb/r/innodb_mysql.result
mysql-test/suite/innodb/t/innodb_mysql.test
mysql-test/t/func_math.test
sql-common/client.c
sql/binlog.cc
sql/item_func.cc
sql/item_subselect.cc
sql/mysqld.cc
sql/sql_acl.cc
sql/sql_array.h
sql/sql_base.cc
sql/sql_parse.cc
sql/sql_select.cc
sql/sql_select.h
storage/innobase/handler/i_s.cc
storage/innobase/lock/lock0lock.c
storage/innobase/que/que0que.c
storage/innobase/srv/srv0start.c
vio/test-ssl.c
vio/test-sslclient.c
vio/test-sslserver.c
vio/viossl.c
vio/viosslfactories.c
vio/viotest-ssl.c
=== modified file 'mysql-test/r/func_str.result'
--- a/mysql-test/r/func_str.result 2011-01-13 08:19:52 +0000
+++ b/mysql-test/r/func_str.result 2011-05-25 14:19:53 +0000
@@ -4306,5 +4306,22 @@ FROM_BASE64(TO_BASE64(dt1))
2011-01-01 02:03:04
DROP TABLE t1;
#
+# Bug#11765562 58545:
+# EXPORT_SET() CAN BE USED TO MAKE ENTIRE SERVER COMPLETELY UNRESPONSIVE
+#
+SELECT @tmp_max:= @@global.max_allowed_packet;
+@tmp_max:= @@global.max_allowed_packet
+1048576
+SET @@global.max_allowed_packet=1024*1024*1024;
+SELECT @@global.max_allowed_packet;
+@@global.max_allowed_packet
+1073741824
+SELECT CHAR_LENGTH(EXPORT_SET(1,1,1,REPEAT(1,100000000)));
+CHAR_LENGTH(EXPORT_SET(1,1,1,REPEAT(1,100000000)))
+NULL
+Warnings:
+Warning 1301 Result of export_set() was larger than max_allowed_packet (1073741824) - truncated
+SET @@global.max_allowed_packet:= @tmp_max;
+#
# End of 5.6 tests
#
=== modified file 'mysql-test/t/func_str.test'
--- a/mysql-test/t/func_str.test 2011-01-13 08:19:52 +0000
+++ b/mysql-test/t/func_str.test 2011-05-25 14:19:53 +0000
@@ -1557,5 +1557,23 @@ SELECT FROM_BASE64(TO_BASE64(dt1)) FROM
DROP TABLE t1;
--echo #
+--echo # Bug#11765562 58545:
+--echo # EXPORT_SET() CAN BE USED TO MAKE ENTIRE SERVER COMPLETELY UNRESPONSIVE
+--echo #
+
+SELECT @tmp_max:= @@global.max_allowed_packet;
+SET @@global.max_allowed_packet=1024*1024*1024;
+# switching connection to allow the new max_allowed_packet take effect
+--connect (newconn, localhost, root,,)
+
+SELECT @@global.max_allowed_packet;
+SELECT CHAR_LENGTH(EXPORT_SET(1,1,1,REPEAT(1,100000000)));
+
+--connection default
+SET @@global.max_allowed_packet:= @tmp_max;
+--disconnect newconn
+
+
+--echo #
--echo # End of 5.6 tests
--echo #
=== modified file 'sql/item_strfunc.cc'
--- a/sql/item_strfunc.cc 2011-05-21 08:25:33 +0000
+++ b/sql/item_strfunc.cc 2011-05-25 14:19:53 +0000
@@ -3437,23 +3437,21 @@ err:
String* Item_func_export_set::val_str(String* str)
{
DBUG_ASSERT(fixed == 1);
- ulonglong the_set = (ulonglong) args[0]->val_int();
- String yes_buf, *yes;
- yes = args[1]->val_str(&yes_buf);
- String no_buf, *no;
- no = args[2]->val_str(&no_buf);
- String *sep = NULL, sep_buf ;
+ String yes_buf, no_buf, sep_buf;
+ const ulonglong the_set = (ulonglong) args[0]->val_int();
+ const String *yes= args[1]->val_str(&yes_buf);
+ const String *no= args[2]->val_str(&no_buf);
+ const String *sep= NULL;
uint num_set_values = 64;
- ulonglong mask = 0x1;
str->length(0);
str->set_charset(collation.collation);
/* Check if some argument is a NULL value */
if (args[0]->null_value || args[1]->null_value || args[2]->null_value)
{
- null_value=1;
- return 0;
+ null_value= true;
+ return NULL;
}
/*
Arg count can only be 3, 4 or 5 here. This is guaranteed from the
@@ -3466,37 +3464,56 @@ String* Item_func_export_set::val_str(St
num_set_values=64;
if (args[4]->null_value)
{
- null_value=1;
- return 0;
+ null_value= true;
+ return NULL;
}
/* Fall through */
case 4:
if (!(sep = args[3]->val_str(&sep_buf))) // Only true if NULL
{
- null_value=1;
- return 0;
+ null_value= true;
+ return NULL;
}
break;
case 3:
{
/* errors is not checked - assume "," can always be converted */
uint errors;
- sep_buf.copy(STRING_WITH_LEN(","), &my_charset_bin, collation.collation, &errors);
+ sep_buf.copy(STRING_WITH_LEN(","), &my_charset_bin,
+ collation.collation, &errors);
sep = &sep_buf;
}
break;
default:
DBUG_ASSERT(0); // cannot happen
}
- null_value=0;
+ null_value= false;
+
+ const ulong max_allowed_packet= current_thd->variables.max_allowed_packet;
+ const uint num_separators= num_set_values > 0 ? num_set_values - 1 : 0;
+ const ulonglong max_total_length=
+ num_set_values * max(yes->length(), no->length()) +
+ num_separators * sep->length();
+
+ if (unlikely(max_total_length > max_allowed_packet))
+ {
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_ALLOWED_PACKET_OVERFLOWED,
+ ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED),
+ func_name(), max_allowed_packet);
+ null_value= true;
+ return NULL;
+ }
- for (uint i = 0; i < num_set_values; i++, mask = (mask << 1))
+ uint ix;
+ ulonglong mask;
+ for (ix= 0, mask=0x1; ix < num_set_values; ++ix, mask = (mask << 1))
{
if (the_set & mask)
str->append(*yes);
else
str->append(*no);
- if (i != num_set_values - 1)
+ if (ix != num_separators)
str->append(*sep);
}
return str;
=== modified file 'unittest/gunit/item-t.cc'
--- a/unittest/gunit/item-t.cc 2011-05-13 09:36:13 +0000
+++ b/unittest/gunit/item-t.cc 2011-05-25 14:19:53 +0000
@@ -176,6 +176,89 @@ TEST_F(ItemTest, ItemFuncDesDecrypt)
}
+TEST_F(ItemTest, ItemFuncExportSet)
+{
+ String str;
+ Item *on_string= new Item_string(STRING_WITH_LEN("on"), &my_charset_bin);
+ Item *off_string= new Item_string(STRING_WITH_LEN("off"), &my_charset_bin);
+ Item *sep_string= new Item_string(STRING_WITH_LEN(","), &my_charset_bin);
+ {
+ // Testing basic functionality.
+ Item_func_export_set *export_set=
+ new Item_func_export_set(new Item_int(2),
+ on_string,
+ off_string,
+ sep_string,
+ new Item_int(4));
+ EXPECT_FALSE(export_set->fix_fields(thd(), NULL));
+ EXPECT_EQ(&str, export_set->val_str(&str));
+ EXPECT_STREQ("off,on,off,off", str.c_ptr_safe());
+ }
+ {
+ // Testing corner case: number_of_bits == zero.
+ Item_func_export_set *export_set=
+ new Item_func_export_set(new Item_int(2),
+ on_string,
+ off_string,
+ sep_string,
+ new Item_int(0));
+ EXPECT_FALSE(export_set->fix_fields(thd(), NULL));
+ EXPECT_EQ(&str, export_set->val_str(&str));
+ EXPECT_STREQ("", str.c_ptr_safe());
+ }
+
+ /*
+ Bug#11765562 58545:
+ EXPORT_SET() CAN BE USED TO MAKE ENTIRE SERVER COMPLETELY UNRESPONSIVE
+ */
+ const ulong max_size= 1024;
+ const ulonglong repeat= max_size / 2;
+ Item *item_int_repeat= new Item_int(repeat);
+ Item *string_x= new Item_string(STRING_WITH_LEN("x"), &my_charset_bin);
+ String * const null_string= NULL;
+ thd()->variables.max_allowed_packet= max_size;
+ {
+ // Testing overflow caused by 'on-string'.
+ Mock_error_handler error_handler(thd(), ER_WARN_ALLOWED_PACKET_OVERFLOWED);
+ Item_func_export_set *export_set=
+ new Item_func_export_set(new Item_int(0xff),
+ new Item_func_repeat(string_x, item_int_repeat),
+ string_x,
+ sep_string);
+ EXPECT_FALSE(export_set->fix_fields(thd(), NULL));
+ EXPECT_EQ(null_string, export_set->val_str(&str));
+ EXPECT_STREQ("", str.c_ptr_safe());
+ EXPECT_EQ(1, error_handler.handle_called());
+ }
+ {
+ // Testing overflow caused by 'off-string'.
+ Mock_error_handler error_handler(thd(), ER_WARN_ALLOWED_PACKET_OVERFLOWED);
+ Item_func_export_set *export_set=
+ new Item_func_export_set(new Item_int(0xff),
+ string_x,
+ new Item_func_repeat(string_x, item_int_repeat),
+ sep_string);
+ EXPECT_FALSE(export_set->fix_fields(thd(), NULL));
+ EXPECT_EQ(null_string, export_set->val_str(&str));
+ EXPECT_STREQ("", str.c_ptr_safe());
+ EXPECT_EQ(1, error_handler.handle_called());
+ }
+ {
+ // Testing overflow caused by 'separator-string'.
+ Mock_error_handler error_handler(thd(), ER_WARN_ALLOWED_PACKET_OVERFLOWED);
+ Item_func_export_set *export_set=
+ new Item_func_export_set(new Item_int(0xff),
+ string_x,
+ string_x,
+ new Item_func_repeat(string_x, item_int_repeat));
+ EXPECT_FALSE(export_set->fix_fields(thd(), NULL));
+ EXPECT_EQ(null_string, export_set->val_str(&str));
+ EXPECT_STREQ("", str.c_ptr_safe());
+ EXPECT_EQ(1, error_handler.handle_called());
+ }
+}
+
+
TEST_F(ItemTest, ItemFuncIntDivOverflow)
{
const char dividend_str[]=
=== modified file 'unittest/gunit/test_utils.h'
--- a/unittest/gunit/test_utils.h 2011-05-13 09:36:13 +0000
+++ b/unittest/gunit/test_utils.h 2011-05-25 14:19:53 +0000
@@ -63,6 +63,8 @@ public:
MYSQL_ERROR::enum_warning_level level,
const char* msg,
MYSQL_ERROR ** cond_hdl);
+
+ int handle_called() const { return m_handle_called; }
private:
THD *m_thd;
uint m_expected_error;
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-trunk branch (tor.didriksen:3118 to 3119) Bug#11765562 | Tor Didriksen | 27 May |