List:Commits« Previous MessageNext Message »
From:Tor Didriksen Date:May 12 2011 2:35pm
Subject:bzr commit into mysql-trunk branch (tor.didriksen:3372) Bug#11765562
View as plain text  
#At file:///export/home/didrik/repo/trunk-bug11765562/ based on revid:tatjana.nuernberg@stripped

 3372 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-05-06 13:32:53 +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-vdcqepjt0t31bvok.bundle
Thread
bzr commit into mysql-trunk branch (tor.didriksen:3372) Bug#11765562Tor Didriksen12 May