#At file:///export/home/didrik/repo/trunk-bug11765562/ based on revid:tor.didriksen@stripped
3359 Tor Didriksen 2011-05-03
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.
@ 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.
Fix an EXPECT_EQ call: the expected value should be first.
modified:
sql/item_strfunc.cc
unittest/gunit/item-t.cc
=== modified file 'sql/item_strfunc.cc'
--- a/sql/item_strfunc.cc 2011-04-15 09:04:21 +0000
+++ b/sql/item_strfunc.cc 2011-05-03 08:51:46 +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,62 @@ 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;
+
+ ulonglong total_length= 0;
+ ulonglong mask;
+ uint ix;
+ for (ix= 0, mask= 0x1; ix < num_set_values; ++ix, mask= (mask << 1))
+ {
+ if (the_set & mask)
+ total_length+= yes->length();
+ else
+ total_length+= no->length();
+ if (ix != num_set_values - 1)
+ total_length+= sep->length();
+ }
+
+ if (total_length > current_thd->variables.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(), current_thd->variables.max_allowed_packet);
+ null_value= true;
+ return NULL;
+ }
- for (uint i = 0; i < num_set_values; i++, mask = (mask << 1))
+ str->reserve(static_cast<uint32>(total_length));
+ 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_set_values - 1)
str->append(*sep);
}
return str;
=== modified file 'unittest/gunit/item-t.cc'
--- a/unittest/gunit/item-t.cc 2011-03-18 12:25:56 +0000
+++ b/unittest/gunit/item-t.cc 2011-05-03 08:51:46 +0000
@@ -66,10 +66,12 @@ public:
const char* msg,
MYSQL_ERROR ** cond_hdl)
{
- EXPECT_EQ(sql_errno, m_expected_error);
+ EXPECT_EQ(m_expected_error, sql_errno);
++m_handle_called;
return true;
}
+
+ int handle_called() const { return m_handle_called; }
private:
THD *m_thd;
uint m_expected_error;
@@ -246,6 +248,88 @@ 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(m_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(m_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);
+ m_thd->variables.max_allowed_packet= max_size;
+ {
+ // Testing overflow caused by 'on-string'.
+ Mock_error_handler error_handler(m_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(m_thd, NULL));
+ EXPECT_EQ(NULL, 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(m_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(m_thd, NULL));
+ EXPECT_EQ(NULL, 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(m_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(m_thd, NULL));
+ EXPECT_EQ(NULL, 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[]=
Attachment: [text/bzr-bundle] bzr/tor.didriksen@oracle.com-20110503085146-n30nxah8iic36y6l.bundle
| Thread |
|---|
| • bzr commit into mysql-trunk branch (tor.didriksen:3359) Bug#11765562 | Tor Didriksen | 3 May |